结构型设计模式 - 组合模式详解
基本介绍
1、组合模式(Composite Pattern)又叫部分整体模式,他创建了对象组的树形结构,将对象组合成树状结构以表示「整体 - 部分」的层次关系。
2、组合模式使得用户对单个对象和组合对象的访问具有一致性,即:组合能让客户以一致的方式处理个别对象以及组合对象
模式结构
Component(抽象构件):定义参加组合对象的公有方法和属性,可以定义一些默认的行为和属性。
Composite(容器构件):树枝对象,它的作用是组合树枝结点和叶子结点形成一个树形结构。
Leaf(叶子构件):叶子构件的下面没有其他分支,也就是遍历的最小单位。
组合模式有两种实现:安全模式和透明模式,其结构如下图所示
安全组合模式:在抽象构件角色中没有声明任何用于管理成员对象的方法,而是在容器构件
Composite
类中声明并实现这些方法。透明组合模式:抽象构建角色中声明了所有用于管理成员对象的方法,对其它构件公开透明。
简单案例
要求:在页面展示出公司的部门组成(一个公司有多个部门,每个部门有多个小组);
这是一种很明显的树形结构,因此可以用组合模式解决
「抽象构件」:OrganizationComponent
public abstract class OrganizationComponent { private String name; public OrganizationComponent(String name) { this.name = name; } protected void add(OrganizationComponent component) { throw new UnsupportedOperationException("不支持添加操作"); } protected void remove(OrganizationComponent component) { throw new UnsupportedOperationException("不支持删除操作"); } protected abstract void print(); public String getName() { return name; } public void setName(String name) { this.name = name; } }
「容器构件」:Company、Department
public class Company extends OrganizationComponent { private List<OrganizationComponent> components = new ArrayList<>(); public Company(String name) { super(name); } @Override protected void add(OrganizationComponent component) { components.add(component); } @Override protected void remove(OrganizationComponent component) { components.remove(component); } @Override protected void print() { System.out.println("======="+getName()+"======="); for (OrganizationComponent component : components) { component.print(); } } @Override public String getName() { return super.getName(); } }
public class Department extends OrganizationComponent { private List<OrganizationComponent> components = new ArrayList<>(); public Department(String name) { super(name); } @Override protected void add(OrganizationComponent component) { components.add(component); } @Override protected void remove(OrganizationComponent component) { components.remove(component); } @Override protected void print() { System.out.println("======="+getName()+"======="); for (OrganizationComponent component : components) { component.print(); } } @Override public String getName() { return super.getName(); } }
「叶子构件」:Group,叶子构件不没有子节点了,所以不需要添加、删除之类的方法
public class Group extends OrganizationComponent { public Group(String name) { super(name); } @Override protected void print() { System.out.println(getName()); } @Override public String getName() { return super.getName(); } }
「测试类」:Client
public class Client { @Test public void test01(){ OrganizationComponent company = new Company("阿里巴巴"); OrganizationComponent department1 = new Department("市场部"); OrganizationComponent department2 = new Department("技术部"); OrganizationComponent group1 = new Group("市场一组"); OrganizationComponent group2 = new Group("市场二组"); OrganizationComponent group3 = new Group("技术一组"); OrganizationComponent group4 = new Group("技术二组"); //添加部门 company.add(department1); company.add(department2); //添加小组 department1.add(group1); department1.add(group2); department2.add(group3); department2.add(group4); //打印结果 company.print(); } }
「运行结果」
=======阿里巴巴======= =======市场部======= 市场一组 市场二组 =======技术部======= 技术一组 技术二组
在 HashMap 中的应用
在 Java(jdk 1.8为例) 的集合类 HashMap 中,抽象构件是 Map,容器构件是 HashMap,叶子构件是 Node
进入源码可以看见,在 Map 中定义了许多公共方法
HashMap 实现了 Map,并对一些方法重写,而且 HashMap 中有一个静态内部类 Node,它就充当了叶子构件的角色,Node 中去除了 put、putAll 等方法,下面也没有子结点了
使用:
@Test public void test02(){ Map<String, String> map = new HashMap<>(); map.put("k1", "v1"); map.put("k2", "v2"); System.out.println(map); }
当我们 put 一个键值对的时候,在 HashMap 内部会调用 putVal 方法,将键值对封装为 Node。
总结
1、简化客户端操作。客户端只需要面对一致的对象而不用考虑整体部分或者节点叶子的问题。
2、具有较强的扩展性。当我们要更改组合对象时,我们只需要调整内部的层次关系,客户端不用做出任何改动。
3、方便创建出复杂的层次结构。客户端不用理会组合里面的组成细节,容易添加节点或者叶子从而创建出复杂的树形结构。
4、需要遍历组织机构,或者处理的对象具有树形结构时,非常适合使用组合模式。
5、要求较高的抽象性。如果节点和叶子有很多差异性的话,比如很多方法和属性都不一样,不适合使用组合模式。