一、什么是组合模式
简介:
- 组合模式(Composite Pattern),又叫部分整体模式,它创建了对象组的树形结构。将对象组合成树状结构以表示“整体-部分”的层次关系。
- 组合模式依据树形结构来组合对象,用来表示部分以及整体层次。
- 组合模式属于结构型模式。
- 组合模式使得用户对单个对象和组合对象的访问具有一致性。即:组合能让客户以一致的方式处理个别对象以及组合对象。
应用场景:
- 银行总行,总行有前台、后勤、网络部门等,辖区下还有地方分行,也有前台、后勤、网络部门,最小的分行就没有子分行了
- 公司也是,总公司下有子公司,每个公司大部分的部门都类似
- 文件夹和文件,都有增加、删除等api,也有层级管理关系
- 当想表达对象的部分-整体的层次结构
- 当我们的要处理的对象可以生成一颗树形结构,我们要对树上的节点和叶子进行操作时,它能够提供一致的方式,而不用考虑它是节点还是叶子
二、组合模式的实现方式
模式结构分析:
这种形式涉及到三个角色:
- 抽象构件(Component)角色 :它是一个抽象接口,表示树根,例子∶总行
- 树枝构件(Composite)角色︰和组合部件类似,也有自己的子节点,例子:总行下的分行
- 树叶构件(Leaf)角色:在组合中表示子节点对象,注意是没有子节点,例子:最小地方的分行
类关系图:
统一模型:
代码实现:
查看代码
/*
*根节点,抽象类,通⽤的属性和⽅法
* */
public abstract class Root {
private String name;
public Root(String name){
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public abstract void addFile(Root root);
public abstract void removeFile(Root root);
public abstract void display(int depth);
}
/*
* 具体的⽂件夹,⾥⾯可以添加⼦⽂件夹或者⽂件
* */
public class Folder extends Root {
List<Root> folders = new ArrayList<>();
public Folder(String name){
super(name);
}
public List<Root> getFolders() {
return folders;
}
public void setFolders(List<Root> folders)
{
this.folders = folders;
}
@Override
public void addFile(Root root) {
folders.add(root);
}
@Override
public void removeFile(Root root) {
folders.remove(root);
}
@Override
public void display(int depth) {
StringBuilder sb = new StringBuilder();
for(int i=0; i<depth;i++){
sb.append("-");
}
//打印横线和当前⽂件名
System.out.println(sb.toString()+this.getName()
);
for(Root r : folders){
//每个下级,横线多2个
r.display(depth+2);
}
}
}
/*
*这个类是没有节点,不⽤存储其他⼦类数组,所以是叶⼦节点
* */
public class File extends Root{
public File(String name){
super(name);
}
@Override
public void addFile(Root root) {
}
@Override
public void removeFile(Root root) {
}
@Override
public void display(int depth) {
StringBuilder sb = new StringBuilder();
for(int i=0; i<depth;i++){
sb.append("-");
}
//打印横线和当前⽂件名
System.out.println(sb.toString()+this.getName()
);
}
}
测试用例:
/*
* 组合模式
* */
@Test
public void compositeDesign(){
//创造根⽂件夹
Root root1 = new Folder("C://");
//建⽴⼦⽂件
Root desktop = new Folder("桌⾯");
Root myComputer = new Folder("我的电脑");
//建⽴⼦⽂件
Root javaFile = new File("HelloWorld.java");
//建⽴⽂件夹关系
root1.addFile(desktop);
root1.addFile(myComputer);
//建⽴⽂件关系
myComputer.addFile(javaFile);
//从0级开始展示,每下⼀级,多2条横线
root1.display(0);
//另外⼀个根
Root root2 = new Folder("D://");
root2.display(0);
}
测试结果:
C://
--桌⾯
--我的电脑
----HelloWorld.java
D://
方法评估:
核心:在客户端可以用一棵树来表示对象。
客户端: 客户端无需再区分操作的是树枝对象(Composite)还是树叶对象(Leaf)了;对于客户端而言,操作的都是Component对象。
优点:
- 客户端只需要面对一致的对象而不用考虑整体部分或者节点叶子的问题。
- 方便创建出复杂的层次结构。
缺点:
- 客户端需要花更多时间理清类之间的层次关系。