简介
在现实生活中,存在很多“部分-整体”的关系,例如,大学中的部门与学院、总公司中的部门与分公司、学习用品中的书与书包、生活用品中的衣服与衣柜、以及厨房中的锅碗瓢盆等。在软件开发中也是这样,例如,文件系统中的文件与文件夹、窗体程序中的简单控件与容器控件等。对这些简单对象与复合对象的处理,如果用组合模式来实现会很方便。
组合(Composite Pattern)模式的定义:有时又叫作整体-部分(Part-Whole)模式,它是一种将对象组合成树状的层次结构的模式,用来表示“整体-部分”的关系,使用户对单个对象和组合对象具有一致的访问性,属于结构型设计模式。
组合模式一般用来描述整体与部分的关系,它将对象组织到树形结构中,顶层的节点被称为根节点,根节点下面可以包含树枝节点和叶子节点,树枝节点下面又可以包含树枝节点和叶子节点,树形结构图如下。

由上图可以看出,其实根节点和树枝节点本质上属于同一种数据类型,可以作为容器使用;而叶子节点与树枝节点在语义上不属于用一种类型。但是在组合模式中,会把树枝节点和叶子节点看作属于同一种数据类型(用统一接口定义),让它们具备一致行为。
这样,在组合模式中,整个树形结构中的对象都属于同一种类型,带来的好处就是用户不需要辨别是树枝节点还是叶子节点,可以直接进行操作,给用户的使用带来极大的便利。
组合模式的主要优点有:
- 组合模式使得客户端代码可以一致地处理单个对象和组合对象,无须关心自己处理的是单个对象,还是组合对象,这简化了客户端代码;
- 更容易在组合体内加入新的对象,客户端不会因为加入了新的对象而更改源代码,满足“开闭原则”;
其主要缺点是:
- 设计较复杂,客户端需要花更多时间理清类之间的层次关系;
- 不容易限制容器中的构件;
- 不容易用继承的方法来增加构件的新功能;
代码实现
我们拿学校、院系、专业举例
package component;/** * 组合模式 * @author zyp * @create 2022/4/26 */public abstract class OrganizationComponent { /** * 名称 */ private String name; /** * 描述 */ private String desc; /** * 构造方法 * @param name * @param desc */ public OrganizationComponent(String name , String desc){ this.name = name; this.desc = desc; } /** * 添加组织 * @param organizationComponent */ public abstract void add(OrganizationComponent organizationComponent); /** * 删除组织 * @param organizationComponent */ public abstract void remove(OrganizationComponent organizationComponent); /** * 打印信息 */ public abstract void print(); public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; }}
学校
package component;import java.util.ArrayList;import java.util.List;/** * 大学 * @author zyp * @create 2022/4/26 */public class University extends OrganizationComponent{ private List organizationComponentList = new ArrayList(); public University(String name , String desc){ super(name,desc); } @Override public void add(OrganizationComponent organizationComponent) { organizationComponentList.add(organizationComponent); } @Override public void remove(OrganizationComponent organizationComponent) { organizationComponentList.remove(organizationComponent); } @Override public void print() { System.out.println(super.getName()); for(OrganizationComponent organizationComponent : organizationComponentList){ organizationComponent.print(); } }}
院系
package component;import java.util.ArrayList;import java.util.List;/** * 院系 * @author zyp * @create 2022/4/26 */public class Department extends OrganizationComponent{ List organizationComponentList = new ArrayList<>(); public Department(String name , String desc){ super(name , desc); } @Override public void add(OrganizationComponent organizationComponent) { organizationComponentList.add(organizationComponent); } @Override public void remove(OrganizationComponent organizationComponent) { organizationComponent.remove(organizationComponent); } @Override public void print() { System.out.println("--------"+super.getName()+"--------"); for(OrganizationComponent organizationComponent : organizationComponentList){ organizationComponent.print(); } }}
专业
package component;/** * 专业 * @author zyp * @create 2022/4/26 */public class Major extends OrganizationComponent{ public Major(String name , String desc){ super(name , desc); } @Override public void add(OrganizationComponent organizationComponent) { throw new RuntimeException("叶子节点无法再添加组织"); } @Override public void remove(OrganizationComponent organizationComponent) { throw new RuntimeException("叶子节点无法再删除组织"); } @Override public void print() { System.out.println(super.getName()); }}
测试类
package component;/** * 组合模式测试类 * @author zyp * @create 2022/4/26 */public class ComponentTest { public static void main(String[] args){ //学校 OrganizationComponent university = new University("温州大学", "不错的大学"); //院系 OrganizationComponent department1 = new Department("瓯江学院", "很好的学院"); OrganizationComponent department2 = new Department("城市学院", "一般学院"); //院系添加专业 department1.add(new Major("数学专业", "一般")); department1.add(new Major("化学专业", "一般")); //院系添加专业 department2.add(new Major("计算机专业", "普通")); department2.add(new Major("商务专业", "好")); //学校添加院系 university.add(department1); university.add(department2); //打印 university.print(); }}
执行结果
