结构型模式 - 组合模式(多个同类型子对象组成整体)

组合模式(Composite Pattern)

简介

组合模式,也叫部分整体模式,用于把一组相似的对象当作一个单一的对象,组合模式依据树形结构来组合对象,用来表示部分以及整体层次。属于结构型模式,创建了对象组的树形结构。

意图

将对象组合树形结构以表示“部分-整体”层次结构。使得用户对单个对象和组合对象的使用具有一致性。

解决问题

主要解决:在树形结构问题中,模糊了简单元素和复杂元素的概念,客户程序可以像处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。
如何解决:树枝和叶子实现统一接口,树枝内部组合该接口。
关键代码:树枝和叶子实现统一接口,树枝内部组合该接口。

特点

  • 优点
  1. 高层模块调用简单;
  2. 节点自由增加。
  • 缺点
    使用组合模式时,叶子和树枝的声明都是实现类,而不是接口,违反了依赖倒置原则

  • 组合模式有两种实现方式

  1. 透明方式
    在Component中声明所有用来管理子对象的方法,其中包括Add, Remove等,这样实现Component接口的所有子类都具备了Add和Remove。这样做的好处是叶节点和枝节点对于外界没有区别,具备完全一致的行为接口。但问题也在这里,因为Leaf类本身不具备Add, Remove功能,实现它没有意义。

  2. 不透明方式
    也是安全的方式,在Component接口中,不去声明Add和Remove方法,那么子类Leaf也不需要去实现。

组合模式 VS 建造者模式

组合模式和建造者模式都是由子对象构成整体,那么它们有什么区别呢?

  1. 组成部分类型
    组合模式强调组成整体的部分,都是同一类型。建造者模式主要是为了表示,通过子部件组装称为完成产品,不要求子部件都是同一类型。
  2. 组成部分和整体的关系
    组合模式体现是整体与部分的层次关系,依据树形结构来组合对象。建造者模式体现的是这个过程,对客户屏蔽创建对象的复杂性。
  3. 组成部分的可变性
    组合模式如果缺少某个部分,整体依然是整体,而且容易添加、删除部分;建造者模式如果缺少某个部分,很可能无法正常工作,无法删除子部件。

应用实例

1.算术表达式包括操作数、操作符和另一个操作数,其中,另一个操作符也可以是操作数、操作符和另一个操作数。
2.JAVA AWT和SWING中,对于Button和Checkbox是树叶,Container是树枝。

通用类图

透明方式类图

不透明方式类图

实现代码

以不透明方式为例

  1. 新建Company抽象类,声明管理子对象的方法
// Company.java
public abstract class Company {
      protected String name;
      
      public Company(String name) {
            this.name = name;
      }
      
      public abstract void add(Company company);
      public abstract void remove(Company company);
      public abstract void display(int dept); // 显示
      public abstract void lineOfDuty(); // 职责
}
  1. 新建具体的公司类ConcreteCompany实现Company
// ConcreteCompany.java
public class ConcreteCompany extends Company {
      private List<Company> children = new ArrayList<Company>();
      
      public ConcreteCompany(String name) {
            super(name);
      }
      
      @Override
      public void add(Company company) {
            children.add(company);
      }
      @Override
      public void remove(Company company) {
            children.remove(company);
      }
      @Override
      public void display(int dept) {
            int tmp = dept;
            while(tmp -- > 0)
                  System.out.print("-");
            System.out.println(name);
            
            for(Company component: children) {
                  component.display(dept + 2);
            }
      }
      @Override
      public void lineOfDuty() {
            for(Company component: children) {
                  component.lineOfDuty();
            }
      }
}
  1. 新建叶子节点HRDepartment, FinanceDepartment
// HRDepartment.java
public class HRDepartment extends Company {
      public HRDepartment(String name) {
            super(name);
      }
      @Override
      public void add(Company company) {
      }
      @Override
      public void remove(Company company) {
      }
      @Override
      public void display(int dept) {
            while(dept -- > 0)
                  System.out.print("-");
            System.out.println(name);
      }
      @Override
      public void lineOfDuty() {
            System.out.println(name + " 员工招聘管理培训");
      }
}

// FinanceDepartment.java
public class FinanceDepartment extends Company {
      public FinanceDepartment(String name) {
            super(name);
      }
      @Override
      public void add(Company company) {
      }
      @Override
      public void remove(Company company) {
      }
      @Override
      public void display(int dept) {
            while(dept -- > 0)
                  System.out.print("-");
            System.out.println(name);
      }
      @Override
      public void lineOfDuty() {
            System.out.println(name + " 公司财务收支管理");
      }
}
  1. 新建客户端类,使用组合模式创建叶子节点和Component节点,并打印层次结构图和职责
// Client.java
public class Client {
      public static void main(String[] args) {
            ConcreteCompany root = new ConcreteCompany("北京总公司");
            root.add(new HRDepartment("总公司人力资源部"));
            root.add(new FinanceDepartment("总公司财务部"));
            
            ConcreteCompany comp = new ConcreteCompany("上海华东分公司");
            comp.add(new HRDepartment("华东分公司人力资源部"));
            comp.add(new FinanceDepartment("华东分公司财务部"));
            root.add(comp);
            
            ConcreteCompany comp1 = new ConcreteCompany("南京办事处");
            comp1.add(new HRDepartment("南京办事处人力资源部"));
            comp1.add(new FinanceDepartment("南京办事处财务部"));
            root.add(comp1);
            
            ConcreteCompany comp2 = new ConcreteCompany("杭州办事处");
            comp2.add(new HRDepartment("杭州办事处人力资源部"));
            comp2.add(new FinanceDepartment("杭州办事处财务部"));
            root.add(comp2);
            
            System.out.println("结构图:");
            root.display(1);
            
            System.out.println("职责:");
            root.lineOfDuty();
      }
}

运行结果

结构图:
-北京总公司
---总公司人力资源部
---总公司财务部
---上海华东分公司
-----华东分公司人力资源部
-----华东分公司财务部
---南京办事处
-----南京办事处人力资源部
-----南京办事处财务部
---杭州办事处
-----杭州办事处人力资源部
-----杭州办事处财务部
职责:
总公司人力资源部 员工招聘管理培训
总公司财务部 公司财务收支管理
华东分公司人力资源部 员工招聘管理培训
华东分公司财务部 公司财务收支管理
南京办事处人力资源部 员工招聘管理培训
南京办事处财务部 公司财务收支管理
杭州办事处人力资源部 员工招聘管理培训
杭州办事处财务部 公司财务收支管理
posted @ 2021-01-12 00:12  明明1109  阅读(296)  评论(0编辑  收藏  举报