博客信息

组合模式Composite(结构模式)

发布时间:『 2019-03-24 02:49』  博客类别:23种设计模式  阅读(653)
  • 术语

    • Component:主体

    • Composite:组合

    • leaf:叶子节点

  • 角色

    • Client 类:组合模式的调用者

    • Component:主体 组织的抽象主体

    • Composite:University/College 非叶子节点的节点 学校/学院

    • leaf:Department 叶子节点

  • 案例

    需求:遍历华东交通大学/东华理工大学下各所属分院下的所有有专业

    • 使用前

    最容易想到的是继承设计方案:专业===》学院===》学校三者成继承关系

package com.javaxl.design.composite.before;

import java.util.ArrayList;
import java.util.List;

/**
* @author 小李飞刀
* @site www.javaxl.com
* @company
* @create  2020-02-23 11:30
* <p>
* 学校
*/
public class Univisity {
  private List<Univisity> Children = new ArrayList<>();

  private String name;

  public Univisity(String name) {
      this.name = name;
  }

  public void setChildren(List<Univisity> children) {
      Children = children;
  }

  public List<Univisity> getChildren() {
      return Children;
  }

  public void print() {
      System.out.println(this.name);
      if (this.Children.size() > 0) {
          for (Univisity child : Children) {
              child.print();
          }
      }

  }
}

class College extends Univisity {

  public College(String name) {
      super(name);
  }
}

class Department extends College {

  public Department(String name) {
      super(name);
  }
}


public class Client {
  public static void main(String[] args) {
      Univisity univisity = new Univisity("华东交通大学");

      College college1 = new College("外语学院");
      College college2 = new College("计算机学院");
      College college3 = new College("土木学院");

      Department department1 = new Department("日语");
      Department department2 = new Department("英语");
      Department department3 = new Department("法语");
      Department department4 = new Department("电气工程及其自动化");
      Department department5 = new Department("计算机专业");
      Department department6 = new Department("土木工程");

      college1.getChildren().add(department1);
      college1.getChildren().add(department2);
      college1.getChildren().add(department3);
      college2.getChildren().add(department4);
      college2.getChildren().add(department5);
      college3.getChildren().add(department6);

      univisity.getChildren().add(college1);
      univisity.getChildren().add(college2);
      univisity.getChildren().add(college3);

//       college1.print();
      univisity.print();

  }
}

思考:如果该学校要新增分院代码该如何处理,某分院新增专业又该如何处理?

上面这种继承的方案,固然能够完成我们的既定项目需求,但是对于项目扩展而言是存在隐患的;

比如List<Univisity> children这个属性,学校与学院才会存在下属组织机构;再比如非叶子结点(学校学院)能够添加组织机构节点,叶子节点(专业)不能,而这些差异性的部分使 “继承方案” 后续的扩展非常的不便;说白了,我们需要考虑当前节点是叶子节点还是非叶子节点;

为了解决这一问题,组合模式应运而生;

  • 使用后


小李飞刀_设计模式

注意List<Univisity> children的位置,非叶子节点有该属性,叶子节点没有,由于在设计的时候已经考虑了其差异性的部分,因此客户端操作的时候就不需要考虑叶子节点的问题了;

package com.javaxl.design.composite.after;

import java.util.ArrayList;
import java.util.List;

/**
* @author 小李飞刀
* @site www.javaxl.com
* @company
* @create  2020-02-23 14:53
*
* Component为主体
* University、College、Department为组合部分Composite
*/
public abstract class Component{
  private String name;

  public String getName() {
      return name;
  }

  public void setName(String name) {
      this.name = name;
  }

  public void add(Component component){
      throw new UnsupportedOperationException("子类视情况覆写此方法");
  }
  public void remove(Component component){
      throw new UnsupportedOperationException("子类视情况覆写此方法");
  }
  public abstract void print();

  @Override
  public boolean equals(Object obj) {
      Component c = (Component) obj;
      return this.getName().equals(c.getName());
  }
}

class Univisity extends Component{
  private List<Component> children = new ArrayList<>();

  public Univisity(String name) {
      this.setName(name);
  }

  public List<Component> getChildren() {
      return children;
  }

  public void setChildren(List<Component> children) {
      this.children = children;
  }

  public void print() {
      System.out.println(this.getName());
      for (Component child : this.children) {
          child.print();
      }
  }

  @Override
  public void add(Component component) {
      this.children.add(component);
  }

  @Override
  public void remove(Component component) {
      this.children.remove(component);
  }
}

class College extends Component{
  private List<Component> children = new ArrayList<>();

  public College(String name) {
      this.setName(name);
  }

  public List<Component> getChildren() {
      return children;
  }

  public void setChildren(List<Component> children) {
      this.children = children;
  }

  public void print() {
      System.out.println(this.getName());
      for (Component child : this.children) {
          child.print();
      }
  }

  @Override
  public void add(Component component) {
      this.children.add(component);
  }

  @Override
  public void remove(Component component) {
      this.children.remove(component);
  }
}

class Department extends Component{
  public Department(String name) {
      this.setName(name);
  }

  public void print() {
      System.out.println(this.getName());
  }

}


public class Client {
  public static void main(String[] args) {
      Univisity univisity = new Univisity("华东交通大学");

      College college1 = new College("外语学院");
      College college2 = new College("计算机学院");
      College college3 = new College("土木学院");

      Department department1 = new Department("日语");
      Department department2 = new Department("英语");
      Department department3 = new Department("法语");
      Department department4 = new Department("电气工程及其自动化");
      Department department5 = new Department("计算机专业");
      Department department6 = new Department("土木工程");

      college1.add(department1);
      college1.add(department2);
      college1.add(department3);
      college2.add(department4);
      college2.add(department5);
      college3.add(department6);

      univisity.add(college1);
      univisity.add(college2);
      univisity.add(college3);

//       college1.print();
      univisity.print();

//       univisity.remove(new College("外语学院"));
      college2.remove(new Department("电气工程及其自动化"));
      System.out.println("==================");
      univisity.print();

  }
}
  • 注意事项及细节

    • 简化客户端操作。客户端只需要面对一致的对象而不用考虑整体部分或者节点叶子的问题

    • 方便创建出复杂的层次结构。客户端不用理会组合里面的组成细节,容易添加节点,从而创建出复杂的树形结构

    • 需要遍历组织机构,或者处理的对象具有树形结构时, 非常适合使用组合模式

注意:要求较高的抽象性,如果节点和叶子有很多差异性的话,比如很多方法和属性都不一样,不适合使用组合模式

  • 应用

    JDK源码HashMap类:addAll方法




总结

  由此可见,我们以前使用的“容器+内容”,其实是通过组合模式实现的,组合模式保证了容器和内容的一致性,容器里面可以套容器,也可以放内容,但是内容已经是叶子结点了,不能继续扩充,还记得我们在抽象工厂方式中使用的模式之中,为了将零件组装成产品,我们就使用了组合模式,非常的有意思,通过递归来遍历所有的内容。组合模式在我们的生活中使用的非常普遍,我们一定要使用好这个模式,理解其中的抽象,特别是add()的定义,抽象类和实现类之间的参数传递,这点至关重要,当然我们又使用了模板方法和迭代器,希望大家能明白模式之间的联系以及相互使用的道理。



关键字:     设计模式  

备案号:湘ICP备19000029号

Copyright © 2018-2019 javaxl晓码阁 版权所有