携手创作,共同成长!这是我参与「掘金日新计划 · 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);
}
}
输出的结果是
如图,在安全模式中,叶子部件只有一个方法,外部调用的时候根本不会出现调用到空方法的问题,但是需要认为判断哪些是叶子部件哪些是合成部件
透明模式
故名思意,透明模式就是抽象类具有叶子部件和合成部件的所有方法,所以到时候不管叶子还是合成均有全部相同的方法,但是对于叶子部件来说有部分方法是不可用的或者无用的,但是对外均符合一个接口的定义。
相对安全模式,只需要修改抽象类的方法即可
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个方法对于叶子部件来说是不应该有的,所以抽象类里的实现是抛出异常。
总结
组合模式我觉得还是比较难以理解的,主要是他们具体用法和功能和“组合”感觉不是太搭边。
总结起来组合模式有以下的优点:
- 可以分层次定义复杂对象,表示局部和全部,客户端可以忽略不同的节点的差异。
- 从高层次调用,可以很顺畅的调用到每一个局部,一致性比较强。
- 节点自由搭配,灵活度比较高。