什么是组合模式(Composite)
概念
组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。
组合模式关注的是对象间的结构,希望能够让调用者在使用一组对象时和使用单个对象没什么区别,屏蔽掉组合对象和单个对象的差别。
个人感觉组合模式应该叫做树形模式,当对象呈现成树形结构时,使用这个模式就非常的好了,建议改名。
组合模式分为两种:透明式组合模式和安全式组合模式。
透明式组合模式:所有的对象都是使用同一个接口,不会区分对象之间的差别,使用者使用起来是区分不了的。树叶构件也会实现树枝构件的方法,但是是空实现,需要抛出异常。
安全式组合模式:树叶构件和树枝构件的接口需要区分开来,在实际使用时需要使用者区分构件,对于使用者来说就失去了透明性,但也不会在调用方法时抛出异常。
优点
- 使用简单,开发过程也简单。使用者不需要关心整体和单个对象的区别。
- 清晰地划分了对象的职责。
- 符合开放封闭原则。想要加新的对象,只需要实现统一的接口即可,不需要修改已有的代码。
缺点
- 有一定的设计难度。需要理清对象间的层级关系,才能够设计出相应的类。
- 随着对象的种类越来越多,整体的结构会变得复杂。
原则
“+”代表遵守,“-”代表不遵守或者不相关
原则 | 开放封闭 | 单一职责 | 迪米特 | 里氏替换 | 依赖倒置 | 接口隔离 | 合成复用 |
---|---|---|---|---|---|---|---|
+ | + | – | – | + | – | + | |
适用场景(动机)
- 希望整体对象和单个对象间在使用上没有差别。
- 希望整体对象呈现树形结构
具体的一些使用场景:菜单、文件夹。
如何实现
想要实现组合模式,需要有以下三样东西:
- 抽象构件(接口/抽象类):作为声明树叶构件和树枝构件的公共接口,定义树叶和树枝的默认行为。如果是安全式组合模式的话就需要有两个抽象接口。
- 树叶构件:需要实现抽象构件,树叶构件没有子节点。
- 树枝构件:需要实现抽象构件,树枝构件有子节点,负责存储和管理子节点。
下面举例在学校中的统计人数,一个学校需要统计人数,就会把任务交给每个年级的年级主任,年级主任再向班长去要人数,最后就有班长来统计人数,然后年级主任再相加,再交给上级。
从这里我们也可以看出这是一个树型的结构,在具体的使用中也会用到递归。
上类图
才想起来IDEA可以写完代码后就可以查看类之间的关系了,亏我之前还自己去画类图,所以我现在已经写完代码了,来粘上我的代码。
上代码
抽象构件:Component
/**
*
* 抽象构件
* Created on 2021/6/1.
*
* @author xuxiaobai
*/
public interface Component {
int sum();
}
复制代码
树枝构件:Composite
/**
* 年级主任
* 树枝构件
* Created on 2021/6/1.
*
* @author xuxiaobai
*/
public class Composite implements Component{
/**年级班长的集合
* 这里建议使用声明的公共接口,这样就能够添加多种对象
* 需要指定特俗的对象时,可以使用对象作为声明
*/
List<Component> leafs=new ArrayList<>();
//加入新的班长
public void add(Component component){
leafs.add(component);
}
/**
* 统计总人数
* @return
*/
@Override
public int sum() {
int sum=0;
for (Component leaf : leafs) {
sum+=leaf.sum();
}
return sum;
}
}
复制代码
树叶构件:Leaf
/**
* 班长
* 树叶构件
* Created on 2021/6/1.
*
* @author xuxiaobai
*/
public class Leaf implements Component {
private int num;
public Leaf(int num){
this.num=num;
}
@Override
public int sum() {
return num;
}
}
复制代码
测试类:
/**
* 组合模式测试类
* Created on 2021/6/1.
*
* @author xuxiaobai
*/
public class CompositeTest {
public static void main(String[] args) {
Composite composite = new Composite();
composite.add(new Leaf(20));
composite.add(new Leaf(30));
composite.add(new Leaf(40));
System.out.println("该年级人数:");
System.out.println(composite.sum());
/**
* 输出结果:
* 该年级人数:
* 90
*/
}
}
复制代码
因为这里的年级主任(树枝构件)和班长(树叶构件)做的事情都是一样的,所有就不存在安全式和透明式一说,如果在多加一些功能,就需要区分出来了。
总结
组合模式,又名树形模式,基本上遵守了七大设计原则,是一个非常优秀的设计模式,特别适用于当组合对象呈现出树形结构的情况,在具体实现中的树枝构件和树叶构件可以有多种多样,可以让整个组合对象呈现出非常复杂的结构。但要使用组合模式,需要一定设计经验和能力,理清对象间的层级关系。