基本需求
- 展示一个学校的结构,比如一个学校下面有多个学院,学院下面有多个系,相当于一个树形结构,对其节点需要进行操作
传统方案
- 学校<-学院<-系 依次继承
- 这种方式,不能很好实现的管理的操作,比如对学院、系的 添加,删除,遍历等,并且他们之间也没有继承关系,使用继承并不合适
基本介绍
-
组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象
-
组合模式依据树形结构来组合对象,用来表示部分以及整体层次
-
这种类型的设计模式属于结构型模式,它创建了对象组的树形结构
-
这种模式创建了一个包含自己对象组的类。该类提供了修改相同对象组的方式
-
组合模式使得用户对单个对象和组合对象的访问具有一致性,即:组合能让客户以一致的方式处理个别对象以及组合对象
-
UML类图(原理)
- 说明
- Component :这是组合中对象声明接口,在适当情况下,实现所有类共有的接口默认行为,用于访问和管理Component 子部件, Component 可以是抽象类或者接口
- Leaf : 在组合中表示叶子节点,叶子节点没有子节点
- Composite :非叶子节点,用于存储子部件,在Component接口中实现子部件的相关操作,比如增加(add),删除,
- Composite 非叶子节点中聚合了多个叶子节点(集合)或者非叶子节点(节点)(一对多),但由于Leaf和Composite都继承Component,所以也就聚合了Component
- 说明
-
UML类图(案例)
-
代码实现
-
@Data @AllArgsConstructor // 提供满参构造 强制子类提供满参构造 public abstract class OrganizationComponent { // 抽象层 Component 子类 Leaf (叶子节点) 和 Composite (非叶子节点) 都继承或实现该类 protected String name; protected String description; // 此处不定义成抽象方法的原因是避免叶子节点强制实现该方法(如果叶子节点很多) , 作为非叶子节点可以重写该方法 public void add(OrganizationComponent organizationComponent) { throw new UnsupportedOperationException(); } public void remove(OrganizationComponent organizationComponent) { throw new UnsupportedOperationException(); } public abstract void print(); }
-
public class University extends OrganizationComponent { // 此处作为第一层级的非叶子节点 实际聚合第二层级非叶子节点 用到了多态 private List<OrganizationComponent> collageList = new ArrayList<>(); public University(String name, String description) { super(name, description); } // 非叶子节点重写add和remove @Override public void add(OrganizationComponent organizationComponent) { this.collageList.add(organizationComponent); } @Override public void remove(OrganizationComponent organizationComponent) { this.collageList.remove(organizationComponent); } // 实现print方法 @Override public void print() { System.out.println("------------" + this.getName() + "------------"); this.collageList.forEach(OrganizationComponent::print); } }
-
public class Collage extends OrganizationComponent { // 此处作为第二层级的非叶子节点 实际聚合叶子节点 用到了多态 private List<OrganizationComponent> departmentList = new ArrayList<>(); public Collage(String name, String description) { super(name, description); } // 非叶子节点重写add和remove @Override public void add(OrganizationComponent organizationComponent) { this.departmentList.add(organizationComponent); } @Override public void remove(OrganizationComponent organizationComponent) { this.departmentList.remove(organizationComponent); } // 实现print方法 @Override public void print() { System.out.println("------------" + this.getName() + "------------"); this.departmentList.forEach(OrganizationComponent::print); } }
-
public class Department extends OrganizationComponent { // 此处作为非叶子节点 不需要重写 add 和 remove 方法(不支持) 使用这两个方法就会调用父类的抛出异常 public Department(String name, String description) { super(name, description); } @Override public void print() { System.out.println(this.getName()); } }
-
public class Client { public static void main(String[] args) { // 创建学校 OrganizationComponent university = new University("xx大学", "xx大学"); // 创建学院 OrganizationComponent collage1 = new Collage("计算机学院", "计算机学院"); OrganizationComponent collage2 = new Collage("信息工程学院", "信息工程学院"); // 创建系 并将系加入到学院 collage1.add(new Department("软件工程", "软件工程")); collage1.add(new Department("网络工程", "网络工程")); collage2.add(new Department("通信工程", "通信工程")); collage2.add(new Department("信息工程", "信息工程")); // 将学院加入到学校 university.add(collage1); university.add(collage2); // 输出 university.print(); } }
-
jdk源码
- jdk中的hashmap就使用到了组合模式
- UML类图
- 说明
- Map接口相当于Component类 中间多了一层抽象层AbstractMap,HashMap作为实现,Node类是HashMap的静态内部类(这样解释有点牵强)
- 说明
注意事项
- 简化客户端操作,客户端只需要面对一致的对象而不用考虑整体部分或者节点叶子的问题
- 具有较强的扩展性,当我们要更改组合对象时,我们只需要调整内部的层次关系,客户端不用做出任何改动
- 方便创建出复杂的层次结构,客户端不用理会组合里面的组成细节,容易添加节点或者叶子从而创建出复杂的树形结构
- 需要遍历组织机构,或者处理的对象具有树形结构时, 非常适合使用组合模式
- 要求较高的抽象性,如果节点和叶子有很多差异性的话,比如很多方法和属性都不一样,不适合使用组合模式