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

设计模式之复合模式

组合模式(Composite Pattern),又称为“整体-部分”(Part-Whole)模式,是一种结构型设计模式。其核心思想是将对象组合成树形结构以表示“部分-整体”的层次关系,使得用户对单个对象和组合对象的使用具有一致性。在组合模式中,客户将单个对象和组合对象同等看待,无需关心自己正在处理的是单个对象还是组合对象。

一、组合模式的角色组成

组合模式通常包含以下几个主要角色:

1、抽象构件(Component)

定义了一个对象的接口,用于访问和管理组件的子对象。可以是接口或抽象类,声明了对象共有的方法,包括用于访问和管理子构件的方法(如增加子构件、删除子构件、获取子构件等)。在透明式组合模式中,还声明了所有子类中的全部方法。

2、树叶构件(Leaf)

在组合中表示叶子节点对象,是组合中的叶节点对象,没有子节点。实现了抽象构件中定义的行为,但对于那些访问及管理子构件的方法,可以通过异常等方式进行处理。

3、容器构件(Composite)/树枝构件(Composite)

在组合中表示容器节点对象,是组合中的分支节点对象,包含子节点。其子节点可以是叶子节点,也可以是容器节点。提供一个集合用于存储子节点,并实现了在抽象构件中定义的行为,包括那些访问及管理子构件的方法。

二、组合模式的实现方式

组合模式的实现根据所实现接口的区别分为两种形式,分别称为安全式组合模式和透明式组合模式。

1、安全式组合模式

管理聚集的方法只出现在树枝构件类中,而不出现在树叶构件类中。抽象构件不定义出管理子对象的方法,这一定义由树枝构件对象给出。缺点是不够透明,因为树叶类和树枝类将具有不同的接口。

2、透明式组合模式

要求所有的具体构件类,不论树枝构件还是树叶构件,均符合一个固定接口。客户端可以一致地处理所有的对象,无须区分是叶子节点还是容器节点。缺点是树叶构件本来没有管理子对象的方法,却要实现它们(空实现或抛异常),这样会带来一些安全性问题。

三、组合模式的应用场景

组合模式适用于需要表示对象的部分-整体层次结构的场景,如:

1、文件系统中的文件和文件夹

2、窗体程序中的简单控件与容器控件

3、图形界面中的菜单项、按钮和其他控件的树形结构

4、表示公司或组织的部门结构

5、XML文档的层次结构解析等

四、代码示例-Java

下面是一个使用透明式组合模式的Java代码示例,用于模拟公司组织架构中的部门及员工统计。

1. 定义抽象构件(Component)

首先,定义一个抽象构件类Department,表示公司部门或员工,包含基本的属性和方法。

abstract class Department {  
    protected String name;  
      
    public Department(String name) {  
        this.name = name;  
    }  
      
    // 定义一个抽象方法,用于统计人数,实际实现由子类完成  
    public abstract int getCount();  
      
    // 添加子部门或员工(在透明组合模式中,所有类都应包含此方法)  
    public void add(Department department) {  
        throw new UnsupportedOperationException("This is a leaf.");  
    }  
      
    // 删除子部门或员工(同样,所有类都应包含此方法)  
    public void remove(Department department) {  
        throw new UnsupportedOperationException("This is a leaf.");  
    }  
      
    // 显示部门或员工信息  
    public void display(int depth) {  
        StringBuilder indent = new StringBuilder();  
        for (int i = 0; i < depth; i++) {  
            indent.append("--");  
        }  
        System.out.println(indent + name + " (人数: " + getCount() + ")");  
    }  
}

2. 实现树叶构件(Leaf)

定义一个员工类Employee,继承自Department,但只包含员工的基本信息,不实现添加和删除子对象的方法。

class Employee extends Department {  
    private int count = 1; // 员工人数默认为1  
      
    public Employee(String name) {  
        super(name);  
    }  
      
    @Override  
    public int getCount() {  
        return count; // 员工人数始终为1  
    }  
      
    // Employee不需要添加或删除子对象的方法,因此不重写add和remove  
}

3. 实现容器构件(Composite)

定义一个部门类Dept,继承自Department,并实现添加、删除子对象和统计人数的功能。

import java.util.ArrayList;  
import java.util.List;  
  
class Dept extends Department {  
    private List<Department> children = new ArrayList<>();  
      
    public Dept(String name) {  
        super(name);  
    }  
      
    @Override  
    public void add(Department department) {  
        children.add(department);  
    }  
      
    @Override  
    public void remove(Department department) {  
        children.remove(department);  
    }  
      
    @Override  
    public int getCount() {  
        int count = 0;  
        for (Department child : children) {  
            count += child.getCount();  
        }  
        return count;  
    }  
      
    @Override  
    public void display(int depth) {  
        super.display(depth);  
        for (Department child : children) {  
            child.display(depth + 1);  
        }  
    }  
}

4. 客户端代码

最后,编写客户端代码来构建公司组织架构并统计总人数。

public class CompanyStructureDemo {  
    public static void main(String[] args) {  
        // 创建部门及员工  
        Dept root = new Dept("总公司");  
        Dept itDept = new Dept("IT部");  
        Dept hrDept = new Dept("人事部");  
        Employee itEmployee1 = new Employee("张三");  
        Employee itEmployee2 = new Employee("李四");  
        Employee hrEmployee1 = new Employee("王五");  
          
        // 构建组织架构  
        root.add(itDept);  
        root.add(hrDept);  
        itDept.add(itEmployee1);  
        itDept.add(itEmployee2);  
        hrDept.add(hrEmployee1);  
          
        // 显示组织架构及统计人数  
        root.display(0);  
        System.out.println("公司总人数: " + root.getCount());  
    }  
}

五、组合模式的优缺点

1、优点

简化客户端代码:客户端可以一致地处理单个对象和组合对象,无需关心自己处理的是单个对象还是组合对象。
高扩展性:更容易在组合体内加入新的对象,客户端不会因为加入了新的对象而更改源代码,满足“开闭原则”。

2、缺点

设计较复杂:客户端需要花更多时间理清类之间的层次关系。
性能问题:由于组合模式中的对象可能被存储在多个地方,可能导致性能问题,特别是在树形结构复杂的情况下。

六、总结

组合模式通过将对象组合成树形结构来表示“部分-整体”的层次关系,简化了客户端代码,提高了系统的扩展性和灵活性。然而,它也存在设计复杂和潜在的性能问题。在实际应用中,应根据具体场景和需求来选择合适的设计模式。


http://www.kler.cn/news/315664.html

相关文章:

  • 高级java每日一道面试题-2024年9月16日-框架篇-Spring MVC和Struts的区别是什么?
  • Redis发布和订阅
  • 波分技术基础 -- Liquid OTN技术特性
  • 高效打造知识图谱,使用LlamaIndex Relik实现实体关联和关系抽取
  • 火车站高铁站站点时刻查询网站计算机毕设/动车站点时刻查询
  • WebRTC编译后替换libwebrtc.aar时提示找不到libjingle_peerconnection_so.so库
  • 基于单片机控制的程控开关电源研究
  • list(一)
  • 基于微信小程序的健身房管理系统
  • ROS第五梯:ROS+VSCode+C++单步调试
  • [Golang] Context
  • GNU链接器(LD):设置入口点(ENTRY命令)的用法及实例解析
  • 科研绘图系列:R语言箱线图(boxplot)
  • error -- unsupported GNU version gcc later than 10 are not supported;(gcc、g++)
  • 计算机毕业设计 基于SpringBoot的小区运动中心预约管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解
  • 【python】深度优先搜索文件夹并移动全部doc文件
  • 自闭症儿童寄宿学校:打造良好的学习和生活环境
  • 速盾:高防cdn除了快还有什么好处?
  • Maven国内镜像(四种)
  • 20240923 每日AI必读资讯
  • vue源码分析(九)—— 合并配置
  • ChromaDB教程_2024最新版(上)
  • 【sgCreateCallAPIFunction】自定义小工具:敏捷开发→调用接口方法代码生成工具
  • Java String trim()方法
  • 如何创建模板提示prompt
  • Linux移植之系统烧写
  • Redis 中 String 字符串类型详解
  • 2024年中国研究生数学建模竞赛B题(华为题目)WLAN组网中网络吞吐量建模一
  • libtorch落地AI项目的一些总结
  • 面试题(八)