设计模式-组合模式
何为组合?
偶像组合?
No,No,No!!!
这里是组合指的是一个类使用另外一个类成为他的成员对象
它是代码重用的两种解决途径之一,另外一种是继承
而组合模式的组合,可以说是总-分结构,也就是总组合分
当然,这是从实际的类关系来看,从形式来看是相同的接口
public class 总{
private 分 分名;
}
现实例子
为了方便管理和沟通,组合的这种逻辑关系在社会中普遍存在
如地方行政制度,郡县制
假设限制皇帝发布一个政令,如果需要独自跑到每个里去颁布会产生很多问题,
如
1.效率问题
个人的时间是很有限的,如果皇帝每次都亲力亲为到底层工作,恐怕大部分时间都会浪费在路上
2.沟通问题
皇帝与里典存在明显的阶级差别,很难直接进行沟通
但如果皇帝向中央机构直接交流,就能完美地解决以上两个问题,其实这和封装思想很像。
代码结构
Component组件接口
抽象组合对象的方法,客户端统一的访问接口
内容
- 未实现的增/删成员对象方法
- 未实现的业务方法
Composite 组件类
实现了组件接口,具有组合能力的节点类
内容
- 类型为组件接口的成员对象集合(常实现为List)
- 已实现增/删成员对象方法
- 实现的业务方法(遍历成员对象集合,进行递归调用它们的业务方法)
Leaf 叶子类
实现了组件接口,不具备具有组合能力的最终类
内容
- 空实现增/删成员对象方法
- 实现的业务方法
实例代码
这里以前面提到的地方行政制度为例
Place 地方接口
/**
* 地方接口,对应Component组件接口
*/
public interface Place {
void addSubPlace(Place place);
void deleteSubPlace(Place place);
void showStruct(Integer layer);
}
Place 地方接口
/**
* 大地方类
* 对应Composite 组件类
*/
public class BigPlace implements Place{
String name;
// 组合
List<Place> subPlaceList = new LinkedList<>();
public BigPlace(String name) {
this.name = name;
}
@Override
public void addSubPlace(Place place) {
subPlaceList.add(place);
}
@Override
public void deleteSubPlace(Place place) {
subPlaceList.remove(place);
}
/**
* 业务方法
* 根据layer层次输出"-"
* 每次组合层数加一
* @param layer
*/
@Override
public void showStruct(Integer layer) {
for (int i = 0; i < layer; i++) {
System.out.print("-");
}
System.out.println(name);
Iterator<Place> iterator = subPlaceList.listIterator();
while(iterator.hasNext()){
iterator.next().showStruct(layer+1);
}
}
}
LocalPlace 本地类
/**
* 本地类
* 对应叶子类
*/
public class LocalPlace implements Place{
String name;
public LocalPlace(String name) {
this.name = name;
}
@Override
public void addSubPlace(Place place) {
}
@Override
public void deleteSubPlace(Place place) {
}
@Override
public void showStruct(Integer layer) {
for (int i = 0; i < layer; i++) {
System.out.print("-");
}
System.out.println(name);
}
}
调用与结果
Place china = new BigPlace("中国");
china.addSubPlace(new LocalPlace("上海市"));
china.addSubPlace(new LocalPlace("香港特别行政区"));
Place GDProvince = new BigPlace("广东省");
GDProvince.addSubPlace(new LocalPlace("广州市"));
GDProvince.addSubPlace(new LocalPlace("深圳市"));
china.addSubPlace(GDProvince);
china.showStruct(1);
System.out.println("-------------");
GDProvince.showStruct(1);
可以看到对于客户端来说,
只需要接触Place接口,完成组合关系,对于任意的Place都可以完成业务方法的调用
适用场景
- 存在多层的组合关系(树状关系)
- 想要忽略节点与叶子之间的差别,统一调用。
与观察者模式的关系
组合模式像是一种扩展的观察者模式
观察者的代码结构
颁布者维护订阅者集合,当条件满足时候,遍历所有订阅者,调用订阅者的通知方法。
相同点
都通过组合,维护了一个成员对象集合
遍历集合,来进行间接调用。
不同点
- 观察者模式中,调用方与被调用方可以不是相同的接口
组合模式中,调用方与被调用方实现了相同的接口,说明了调用方与被调用方的地位是对等的 - 观察者模式中,被调用方一般不会继续调用,是两层的调用结构
组合模式中,被调用方可能还会继续调用,是多层的调用结构。