1. 意图
将对象组合成树形结构以表示“部分-整体”的层次结构。Composite使得用户对单个对象
和组合对象的使用具有一致性
2. 动机
栗子的公司需要做一个文件的浏览系统,要求可以浏览文件夹和各种文件,栗子很快拿出了v1.0版的方案:做了一个文件夹类,两个具体的文件类(txt,img)
很快他发现,如果需要增加一个zip类型,他需要新增一个ZipFile,并且需要修改原来的Folder类,违反了开闭原则(Open Closed Principle,OCP)
3. 适用性
- 适用于解决整体-部分结构类型的问题
- 客户端希望忽略整体与部分的差异,从而统一的使用它们
4. 结构(透明式的组合模式)
5. 参与者
- 容器:是一个抽象类,统一的表示整体和部分
- 组合:既可以当作节点,也可以当作容器
- 叶子:节点对象
6. 代码示例
- 容器
package com.lt.component;
/**
* @author lt
* @date 2019年4月17日
* @version v1.0
*/
public abstract class Component {
public abstract boolean add(Component e);
public abstract boolean remove(Component e);
public abstract Component getChild(int index);
public abstract void getMsg();
}
- 组合
package com.lt.composite;
import java.util.ArrayList;
import java.util.List;
import com.lt.component.Component;
/**
* @author lt
* @date 2019年4月17日
* @version v1.0
*/
public class Folder extends Component {
private List<Component> list = new ArrayList<>();
private String name;
public Folder(String name){
this.name = name;
}
@Override
public boolean add(Component e) {
return list.add(e);
}
@Override
public boolean remove(Component e) {
return list.remove(e);
}
@Override
public Component getChild(int index) {
return list.get(index);
}
@Override
public void getMsg() {
System.out.println("文件夹:"+name);
for(Component e : list){
e.getMsg();
}
}
}
- 叶子
package com.lt.life;
import com.lt.component.Component;
/**
* @author lt
* @date 2019年4月17日
* @version v1.0
*/
public class ImgFile extends Component {
private String name;
public ImgFile(String name){
this.name = name;
}
@Override
public boolean add(Component e) {
throw new RuntimeException("leaf无法添加子元素");
}
@Override
public boolean remove(Component e) {
throw new RuntimeException("leaf无法删除");
}
@Override
public Component getChild(int index) {
throw new RuntimeException("leaf没有子元素");
}
@Override
public void getMsg() {
System.out.println("图像文件:"+name);
}
}
package com.lt.life;
import com.lt.component.Component;
/**
* @author lt
* @date 2019年4月17日
* @version v1.0
*/
public class TxtFile extends Component {
private String name;
public TxtFile(String name){
this.name = name;
}
@Override
public boolean add(Component e) {
throw new RuntimeException("leaf无法添加子元素");
}
@Override
public boolean remove(Component e) {
throw new RuntimeException("leaf无法删除");
}
@Override
public Component getChild(int index) {
throw new RuntimeException("leaf没有子元素");
}
@Override
public void getMsg() {
System.out.println("文本文档:"+name);
}
}
7. 已知应用
Java SE中的AWT,和Swing大量使用了组合模式,Component类是抽象构件,Checkbox、Button和TextComponent是叶子构件,而Container是容器构件
8. 相关模式
- 通常部件-父部件连接用于责任链模式模式。
- 装饰者模式经常与组合模式一起使用。当装饰和组合一起使用时,它们通常有一个公共的父类。因此装饰必须支持具有Add、Remove和GetChild操作的Component
- 享元模式让你共享组件,但不再能引用他们的父部件。
- Itertor(5.4)可用来遍历Composite。
- Visitor(5.11)将本来应该分布在Composite和Leaf类中的操作和行为局部化。