一文带你理解组合模式

组合设计模式也叫部分整体设计模式,是一种结构型设计模式,它将一组相似的对象看做一个对象来处理,从而可以一视同仁的对所有对象进行统一的访问。在Java系统中,一般以树形结构来形容这种组合关系。

定义

将对象组合成树状结构以表示部分-整体的层次结构,使得外部对单个对象和对象集合的访问具有一致性。

场景

  1. 需要表示对象的部分-整体结构时
  2. 从一个整体中能够独立出部分模块或者功能的场景

角色

抽象根节点

为组合中的对象声明的接口,当然也可以实现一些缺省行为和共有逻辑

枝干节点

定义有子节点的枝干节点的行为,存储子节点,实现抽象根节点中跟子节点有关的操作

叶子节点

定义树形结构中那些没有子节点的叶子节点的行为

分类

根据抽象根节点定义的行为方法的状况,组合模式可以分为透明组合模式和安全组合模式。

透明组合模式

抽象根节点类中定义了组合对象所有的行为方法。在引用时,可以直接接口引用

安全组合模式

抽象根节点类只定义了组合对象的公用行为方法。子节点的接口由自己来定义,在引用时,需要实例类引用

代码说明

组合设计模式在实际开发中使用频率不是非常高,一般这种设计模式在软件系统中,会由系统自身来实现一些系统层面的模块或者框架。现在假设有这样一个场景,一个公司下面有多个部门,部门由具体的成员构成。当需要遍历整个公司的职员时,我们可以采用组合设计模式来递归访问,在本例中,我们采用透明组合模式来实现。
针对公司的所有职员,都可以抽象成一个接口。

/**
 * 组合模式抽象根节点:公司职员抽象接口
 */
public interface IStaff {

  /**
   * 枝干节点获取子节点的方法
   */
  IStaff getChild(int index);

  /**
   * 枝干节点增加子节点的方法
   */
  void addChild(IStaff child);

  /**
   * 枝干节点移除子节点的方法
   */
  void removeChild(IStaff child);

  /**
   * 组和对象共有的行为方法
   */
  void information();
}

可以看到,透明模式是需要根节点不仅仅定义共有的行为方法,还需要定义枝干节点跟叶子节点交互的方法

接下来,需要实现枝干节点和叶子节点。

枝干节点:部门。

/**
 * 枝干节点:部门
 */
public class Department implements IStaff {

  /**
   * 部门名称
   */
  private String name;

  /**
   * 部门内部员工
   */
  private List<IStaff> mems = new ArrayList<>();

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

  @Override public IStaff getChild(int index) {
    if (index < mems.size()) {
      return mems.get(index);
    }
    return null;
  }

  @Override public void addChild(IStaff child) {
    mems.add(child);
  }

  @Override public void removeChild(IStaff child) {
    mems.remove(child);
  }

  @Override public void information() {
    System.out.println("***部门 " + name + "***");
    for (IStaff staff : mems
    ) {
      staff.information();
    }
  }
}

叶子节点:普通员工。

/**
 * 叶子节点:普通员工
 */
public class Staff implements IStaff {
  private String name;

  private String position;

  public Staff(String name, String position) {
    this.name = name;
    this.position = position;
  }

  /**
   * 叶子节点空实现
   */
  @Override public IStaff getChild(int index) {
    return null;
  }

  /**
   * 叶子节点空实现
   */
  @Override public void addChild(IStaff child) {

  }

  /**
   * 叶子节点空实现
   */
  @Override public void removeChild(IStaff child) {

  }

  @Override public void information() {
    System.out.println("员工:姓名 " + name + ", 职位 " + position);
  }
}

上文中,我们只实现了两级结构,实际上,一般会有多级结构。现在我们手动构造一个部门,然后来对该部门进行遍历。

  public static void main(String[] args) {
    // 构建组合对象树形结构,仅构建了两级
    IStaff dep = new Department("技术产品部");
    dep.addChild(new Staff("robin","算法工程师"));
    dep.addChild(new Staff("martin","产品经理"));
    dep.addChild(new Staff("jackMa","销售顾问"));
    // 遍历部门
    dep.information();
  }

对应输出为:

***部门 技术产品部***
员工:姓名 robin, 职位 算法工程师
员工:姓名 martin, 职位 产品经理
员工:姓名 jackMa, 职位 销售顾问

关于源码

安卓系统源码中,视图体系View就是运用了组合模式。View是根节点,定义了所有的共有行为方法;ViewGroup的各种实现类是枝干节点,他们具备操作子视图的addView等方法;View的非容器实现类是叶子节点,叶子节点不具备枝干节点操作子视图的功能。这里安卓将所有枝干节点又进行了一次抽象,使得ViewGroup具备了容器的功能。在这种设计模式下,在对视图进行遍历时,可以一视同仁的对待每一个控件(都是View类型对象)。

总结

事实上,在应用开发中组合模式使用频率比较低。因为这种设计模式在UI架构体系中使用较多,而这种体系一般又会由操作系统自身来实现。组合模式是通过继承来实现的,在灵活性上有一定的局限性,而且枝干节点的职责有溢出,不符合类的单一职责原则。但是组合设计模式的优点也很明显,他提供了一种简单的方式来对相似的集合对象进行递归访问。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值