设计模式之组合模式

97 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第14天,点击查看活动详情

简介

组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。

我对组合模式的理解是有一组对象,他们之前的属性或者方法有一定的不同,或大或小,但是我们不想分别去定义它,而是先抽象出一个统一的概念出来,进行一致的处理。大部分树形结构的概念都可以使用此模式,比如公司->事业部->部门->小组->个人;国家->省->市->区;还有windows的文件系统磁盘->文件夹->文件,都可以理解为部分和整体。

而组合模式中通常有3种参与者:

  • 抽象构件 就是前文所述的抽象出的统一的概念,如公司中的组织,文件系统中的File,一般情况下此抽象构件中包含可以抽象出来的属性和方法,它一般是接口或者抽象类。
  • 叶子部件 即没有下级的对象。一般情况下它的属性或方法是最少的。
  • 合成部件 用来储存和包含其他部件,如叶子部件,它的方法或属性相对叶子更多

案例

组合模式有两种不同的实现模式即 安全模式 透明模式

安全模式

以省市区来做例子,将区域抽象成地区单位AreaUnit,它包含一个属性名称(name)和一个打印所有子组件的方法show()

public abstract class AreaUnit {
    private String name;
    public AreaUnit(String name) {
        this.name = name;
    }
    public abstract void show();
}

定义一个合成部件

public class ParentArea extends AreaUnit {
    private List<AreaUnit> subArea = new ArrayList<>();

    public ParentArea(String name) {
        super(name);
    }
    public void add(AreaUnit areaUnit) {
        this.subArea.add(areaUnit);
    }
    public void del(AreaUnit areaUnit) {
        this.subArea.remove(areaUnit);
    }
    @Override
    public void show(Integer level) {
        for (int i = 0; i < level; i++) {
            System.out.print("  ");
        }
        System.out.println(name + ": ");
        for (AreaUnit component : subArea) {
            component.show(level + 1);
        }
    }
}

以及一个叶子部件

public class SubArea extends AreaUnit {
    public SubArea(String name) {
        super(name);
    }

    @Override
    public void show(Integer level) {
        for (int i = 0; i < level; i++) {
            System.out.print("  ");
        }
        System.out.println(name);
    }
}

应用类

public class App {
    public static void main(String[] args) {
        ParentArea folderRoot = new ParentArea("中国");
        folderRoot.add(new SubArea("北京市"));
        folderRoot.add(new SubArea("天津市"));

        ParentArea folderLevel1 = new ParentArea("江苏省");
        folderLevel1.add(new SubArea("苏州市"));
        folderRoot.add(folderLevel1);

        ParentArea folderLevel2 = new ParentArea("南京市");
        folderLevel2.add(new SubArea("鼓楼区"));
        folderLevel2.add(new SubArea("玄武区"));
        folderLevel1.add(folderLevel2);

        folderRoot.add(new SubArea("上海市"));

        folderRoot.show(0);
    }
}

输出的结果是

图片.png

如图,在安全模式中,叶子部件只有一个方法,外部调用的时候根本不会出现调用到空方法的问题,但是需要认为判断哪些是叶子部件哪些是合成部件

透明模式

故名思意,透明模式就是抽象类具有叶子部件和合成部件的所有方法,所以到时候不管叶子还是合成均有全部相同的方法,但是对于叶子部件来说有部分方法是不可用的或者无用的,但是对外均符合一个接口的定义。

相对安全模式,只需要修改抽象类的方法即可

public abstract class AreaUnit {
    protected String name;
    public AreaUnit(String name) {
        this.name = name;
    }
    public void add(AreaUnit areaUnit) {
        throw new UnsupportedOperationException("对象不支持此功能");
    };
    public void del(AreaUnit areaUnit) {
        throw new UnsupportedOperationException("对象不支持此功能");
    };
    public abstract void show(Integer level);
}

在抽象部件里增加之前没有的add和del方法,这个时候叶子部件也拥有了此2个方法,但是这2个方法对于叶子部件来说是不应该有的,所以抽象类里的实现是抛出异常。

总结

组合模式我觉得还是比较难以理解的,主要是他们具体用法和功能和“组合”感觉不是太搭边。

总结起来组合模式有以下的优点:

  • 可以分层次定义复杂对象,表示局部和全部,客户端可以忽略不同的节点的差异。
  • 从高层次调用,可以很顺畅的调用到每一个局部,一致性比较强。
  • 节点自由搭配,灵活度比较高。