当前位置: 首页 > article >正文

23种设计模式之组合设计模式

文章目录

  • 1. 简介
  • 2. 代码
    • 2.1 Employee (三合一)
    • 2.2 Test
    • 2.3 其他例子
  • 3. 使用场景
  • 4. 优缺点
  • 5. 总结

1. 简介

组合设计模式Composite Pattern)是一种结构型设计模式。它允许你将对象组合成树形结构来表示 “部分 - 整体” 的层次关系。组合模式使得用户对单个对象和组合对象的使用具有一致性,即可以像操作单个对象一样操作组合对象。

  • 结构组成
    • 组件(Component)接口或抽象类 :这是组合模式中的最顶层抽象,它定义了叶子节点和组合节点(包含其他子节点的节点)的公共操作接口。例如,在一个文件系统的模拟中,这个接口可能包含诸如getName()(获取名称)、getSize()(获取大小)等方法。
    • 叶子节点(Leaf):叶子节点是树形结构中的最底层对象,它没有子节点。它们实现了组件接口,但因为没有子节点,所以对于组合相关的操作(如添加或删除子节点)没有实际意义。例如,在文件系统中,文件就是叶子节点,它有自己的名称和大小,但不能包含其他文件或文件夹。
    • 组合节点(Composite):组合节点是包含子节点的节点,它也实现了组件接口。它内部维护了一个子节点的集合,并且实现了添加、删除和获取子节点等操作。在文件系统示例中,文件夹就是组合节点,它可以包含文件和其他文件夹。

2. 代码

2.1 Employee (三合一)

import java.util.ArrayList;
import java.util.List;

public class Employee {
    private String name;
    private String position;
    private int salary;

    private List<Employee> employees;

    public Employee(String name, String position, int salary) {
        this.name = name;
        this.position = position;
        this.salary = salary;
        employees = new ArrayList<>();
    }

    public void addEmployee(Employee employee) {
        employees.add(employee);
    }

    public void removeEmployee(Employee employee) {
        employees.remove(employee);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPosition() {
        return position;
    }

    public void setPosition(String position) {
        this.position = position;
    }

    public int getSalary() {
        return salary;
    }

    public void setSalary(int salary) {
        this.salary = salary;
    }

    public List<Employee> getEmployees() {
        return employees;
    }

    public void setEmployees(List<Employee> employees) {
        this.employees = employees;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", position='" + position + '\'' +
                ", salary=" + salary +
                '}';
    }
}

2.2 Test

public class Test {
    public static void main(String[] args) {
        // CEO
        Employee ceo = new Employee("dev1", "ceo", 10000);
        // 部门经理
        Employee manager = new Employee("dev2", "manager", 5000);
        // 创建销售员
        Employee saller1 = new Employee("dev3", "saller1", 4000);
        Employee saller2 = new Employee("dev3", "saller2", 4000);
        // 仓库管理员
        Employee warehouse = new Employee("dev4", "warehouse", 3000);

        ceo.addEmployee(manager);
        manager.addEmployee(saller1);
        manager.addEmployee(saller2);
        manager.addEmployee(warehouse);

        System.out.println(ceo);
        for(Employee employee : ceo.getEmployees()){
            System.out.println(employee);
            for(Employee e : employee.getEmployees()){
                System.out.println(e);
            }
        }
    }
}

输出结果:

Employee{name='dev1', position='ceo', salary=10000}
Employee{name='dev2', position='manager', salary=5000}
Employee{name='dev3', position='saller1', salary=4000}
Employee{name='dev3', position='saller2', salary=4000}
Employee{name='dev4', position='warehouse', salary=3000}

2.3 其他例子

// 组件接口
interface FileSystemComponent {
    String getName();
    long getSize();
}
// 叶子节点 - 文件
class File implements FileSystemComponent {
    private String name;
    private long size;
    public File(String name, long size) {
        this.name = name;
        this.size = size;
    }
    @Override
    public String getName() {
        return name;
    }
    @Override
    public long getSize() {
        return size;
    }
}
// 组合节点 - 文件夹
class Directory implements FileSystemComponent {
    private String name;
    private java.util.ArrayList<FileSystemComponent> children = new java.util.ArrayList<>();
    public Directory(String name) {
        this.name = name;
    }
    @Override
    public String getName() {
        return name;
    }
    @Override
    public long getSize() {
        long size = 0;
        for (FileSystemComponent child : children) {
            size += child.getSize();
        }
        return size;
    }
    public void add(FileSystemComponent component) {
        children.add(component);
    }
    public void remove(FileSystemComponent component) {
        children.remove(component);
    }
    public FileSystemComponent[] getChildren() {
        return children.toArray(new FileSystemComponent[0]);
    }
}

3. 使用场景

  • 树形结构数据表示:组合模式非常适合用于表示具有层次结构的数据,如文件系统、组织结构图、菜单系统等。例如,在一个公司的组织结构中,部门可以包含子部门和员工,使用组合模式可以方便地对整个组织结构进行操作,如计算部门的总人数、获取部门的所有下属等。
  • 统一处理对象和对象集合:当需要以相同的方式处理单个对象和对象集合时,组合模式是很好的选择。比如在图形绘制系统中,图形可以是单个的点、线,也可以是由多个图形组成的复杂图形。通过组合模式,可以统一地对这些图形进行绘制、移动、缩放等操作。

4. 优缺点

  • 优点
    • 层次结构清晰:组合模式能够清晰地表示出对象之间的层次关系,使得代码结构更加直观,易于理解和维护。
    • 客户端调用简单:客户端可以统一地使用组件接口来操作单个对象和组合对象,不需要分别处理不同类型的对象,降低了客户端代码的复杂性。
    • 可扩展性强:可以方便地添加新的叶子节点或组合节点类型,只要它们实现了组件接口,就可以融入到现有的层次结构中。
  • 缺点
    • 设计复杂度过高:对于简单的层次结构,使用组合模式可能会使设计变得过于复杂,增加了代码的理解和实现成本。
    • 限制了叶子节点和组合节点的差异性:由于叶子节点和组合节点都要实现组件接口,可能会导致一些不符合实际情况的接口实现。例如,叶子节点可能不需要实现与子节点相关的操作,但为了符合接口要求,也需要提供这些操作的空实现。

5. 总结

无,哈哈


http://www.kler.cn/a/419868.html

相关文章:

  • ElasticSearch easy-es 聚合函数 group by 混合写法求Top N 词云 分词
  • 【Spring】介绍一下 Spring 的 xml 标签以及 Bean 的常用配置
  • CAD 二次开发入门与实践:以 C# 为例
  • Bert+CRF的NER实战
  • VSCode如何关闭Vite项目本地自启动
  • 新质驱动·科东软件受邀出席2024智能网联+低空经济暨第二届湾区汽车T9+N闭门会议
  • CTF-PWN: 全保护下格式化字符串利用 [第一届“吾杯”网络安全技能大赛 如果能重来] 赛后学习
  • 题海拾贝——环状序列(ACM/ICPC Seoul 2004,UVa1584)
  • 代码设计:设计模式:应对变化
  • Vue:使用 KeepAlive 缓存切换掉的 component
  • 【机器学习】机器学习学习笔记 - 无监督学习 - k-means/均值漂移聚类/凝聚层次聚类/近邻传播聚类 - 05
  • 【JavaScript】下拉框的实现
  • leetcode530:二叉搜索树的最小绝对值差
  • GitHub Copilot革命性更新:整合顶尖AI模型,如何重塑开发体验?
  • 用 React 编写一个笔记应用程序
  • SQL优化与性能——C++与SQL性能优化
  • 重学设计模式-建造者模式
  • 题海拾贝——生成元(Digit Generator,ACM/ICPC SEOUL 2005,UVa1583)
  • 15.三数之和 python
  • 深度学习模型:门控循环单元(GRU)详解
  • Web基础
  • java中的运算符
  • Elasticsearch面试内容整理-面试注意事项
  • Python 深度学习框架之Keras库详解
  • AI在线免费视频工具4:AI视频编辑ai-video-composer
  • 2024.12.2工作复盘