设计模式---组合(Composite)模式

1 引言

在编辑Word中,我们经常遇到有时需要对一个字进行编辑,有时需要对一段文字进行编辑,一个字或者一行字的编辑行为是相同的。抽象出来就是整体部分的关系,对应就是组合设计模式。

2 定义

组合设计模式,有时又叫作整体-部分(Whole-Part)模式,它是一种将对象组合成树状的层次结构的模式,用来表示“整体-部分”的关系,使用户对单个对象和组合对象具有一致的操作性与访问性,属于结构型设计模式。

组合模式一般用来描述整体与部分的关系,它将对象组织到树形结构中,顶层的节点被称为根节点,根节点下面可以包含树枝节点和叶子节点,树枝节点下面又可以包含树枝节点和叶子节点。

3 结构与实现

组合模式结构与实现并不复杂,主要就是抽象构建(Component)角色,其次是树叶(Leaf)角色与树枝(Composite)构件角色。

  1. 抽象构件(Component)角色:它的主要作用是为树叶构件和树枝构件声明公共接口,并实现它们的默认行为。在透明式的组合模式中抽象构件还声明访问和管理子类的接口;在安全式的组合模式中不声明访问和管理子类的接口,管理工作由树枝构件完成。(总的抽象类或接口,定义一些通用的方法,比如新增、删除)
  2. 树叶构件(Leaf)角色:是组合中的叶节点对象,它没有子节点,用于继承或实现抽象构件。
  3. 树枝构件(Composite)角色 / 中间构件:是组合中的分支节点对象,它有子节点,用于继承和实现抽象构件。它的主要作用是存储和管理子部件,通常包含 Add()、Remove()、GetChild() 等方法。

抽象构件角色分为透明模式与安全模式。

透明模式,抽象构件声明了所有子类中的全部方法,所以客户端无须区别树叶对象和树枝对象,对客户端来说是透明的。但其缺点是:树叶构件本来没有 Add()、Remove() 及 GetChild() 方法,却要实现它们(空实现或抛异常),这样会带来一些安全性问题。图片来自引用2。

 安全模式,将管理子构件的方法移到树枝构件中,抽象构件和树叶构件没有对子对象的管理方法,这样就避免了上一种方式的安全性问题,但由于叶子和分支有不同的接口,客户端在调用时要知道树叶对象和树枝对象的存在,所以失去了透明性。图片来自引用2。

4 优缺点

主要优点有:

  1. 组合模式使得客户端代码可以一致地处理单个对象和组合对象,无须关心自己处理的是单个对象,还是组合对象,这简化了客户端代码;
  2. 更容易在组合体内加入新的对象,客户端不会因为加入了新的对象而更改源代码,满足“开闭原则”。

其主要缺点是:

  1. 设计较复杂,客户端需要花更多时间理清类之间的层次关系;
  2. 不容易限制容器中的构件;
  3. 不容易用继承的方法来增加构件的新功能。

5 引用场景

1.在需要表示一个对象整体与部分的层次结构的场合。

2.要求对用户隐藏组合对象与单个对象的不同,用户可以用统一的接口使用组合结构中的所有对象的场合。

6 代码示例

以我现在所在单位为例,抽象了一个模型,如下图所示:

6.1 公司抽象接口 Company

public interface Company {

    /**
     * 获取公司名称
     * @return 名称
     */
    String getName();

    /**
     * 添加
     * @param c 公司
     */
    void add(Company c);

    /**
     * 移除
     * @param c 公司
     */
    void remove(Company c);

    /**
     * 显示
     * @param depth 层级
     */
    void disPlay(int depth);

    /**
     * 展示职责
     */
    void displayDuty();
}

6.2 具体公司  ConcreteCompany

public class ConcreteCompany implements Company{
    private final List<Company> children = new ArrayList<>();

    private final String name;
    public ConcreteCompany(String name){
        this.name = name;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public void add(Company c) {
        children.add(c);
    }

    @Override
    public void remove(Company c) {
        children.remove(c);
    }

    @Override
    public void disPlay(int depth) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < depth; i++) {
            sb.append("-");
        }
        System.out.println(sb.toString() + getName());
        for (Company c: children) {
            c.disPlay(depth + 2);
        }
    }

    @Override
    public void displayDuty() {
        for (Company c: children) {
            c.displayDuty();
        }
    }
}

6.3 人力资源部门 HumanResourceDepartment

public class HumanResourceDepartment implements Company{

    private String name;
    public HumanResourceDepartment(String name){
        this.name = name;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public void add(Company c) {

    }

    @Override
    public void remove(Company c) {

    }

    @Override
    public void disPlay(int depth) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < depth; i++) {
            sb.append("-");
        }
        System.out.println(sb.toString() + getName());
    }

    @Override
    public void displayDuty() {
        System.out.println(MessageFormat.format("{0}负责管理公司人事所有事务", name));
    }
}

6.4 财务部 FinanceDepartment

public class FinanceDepartment implements Company {

    private String name;
    public FinanceDepartment(String name){
        this.name = name;
    }
    @Override
    public String getName() {
        return name;
    }

    @Override
    public void add(Company c) {

    }

    @Override
    public void remove(Company c) {

    }

    @Override
    public void disPlay(int depth) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < depth; i++) {
            sb.append("-");
        }
        System.out.println(sb.toString() + getName());
    }

    @Override
    public void displayDuty() {
        System.out.println(MessageFormat.format("{0}负责管理公司财务所有事务", name));
    }
}

6.5 主函数

public class Main {
    public static void main(String[] args) {
        //海南分院
        ConcreteCompany haiNanBranch = new ConcreteCompany("海南分院");
        haiNanBranch.add(new HumanResourceDepartment("海南分院人事处"));
        haiNanBranch.add(new FinanceDepartment("海南分院财务处"));

        //云南分院
        ConcreteCompany yunNanBranch = new ConcreteCompany("云南分院");
        yunNanBranch.add(new HumanResourceDepartment("云南分院人事处"));
        yunNanBranch.add(new FinanceDepartment("云南分院财务处"));

        //总院
        ConcreteCompany institute = new ConcreteCompany("天津总院");
        institute.add(new HumanResourceDepartment("总院人力资源部"));
        institute.add(new FinanceDepartment("总院资产财务部"));
        institute.add(haiNanBranch);
        institute.add(yunNanBranch);

        System.out.println("结构图:");
        institute.disPlay(0);
        System.out.println("\n职责:");
        institute.displayDuty();
    }
}

6.6 运行结果

7 引用

1.《大话设计模式》  

2.组合模式(详解版)

8 源代码

design-pattern-learning/src/com/hz/design/pattern/composite at main · airhonor/design-pattern-learning · GitHub

猜你喜欢

转载自blog.csdn.net/honor_zhang/article/details/120885117
今日推荐