设计模式 09 组合模式
组合模式(Composite Pattern)属于结构型模式
概述
组合模式实际上就是将多个组件进行组合,让用户可以对它们进行一致性处理。
比如文件夹,一个文件夹中可能包含有很多个子文件夹或是文件。它就像是一个树形结构一样,有分支有叶子,而组合模式则是可以对整个树形结构上的所有节点进行递归处理,比如我们现在希望将所有文件夹中的文件的名称前面都添加一个前缀,那么就可以使用组合模式。
代码实现
1、定义组件
/**
* 组件
*/
public abstract class Component {
/**
* 添加子组件
* @param component 组件
*/
public abstract void add(Component component);
/**
* 删除子组件
* @param component 组件
*/
public abstract void remove(Component component);
/**
* 获取子组件
* @param index 组件序号
* @return 子组件
*/
public abstract Component getChild(int index);
/**
* 修改名称
*/
public abstract void editName();
}
2、定义文件夹
/**
* 目录
* <p>目录可以包含多个文件或目录
*/
public class Directory extends Component{
/**
* 使用 List 来存放目录中的子组件
*/
List<Component> child = new ArrayList<>();
@Override
public void add(Component component) {
child.add(component);
}
@Override
public void remove(Component component) {
child.remove(component);
}
@Override
public Component getChild(int index) {
return child.get(index);
}
@Override
public void editName() {
// 继续调用所有子组件的 editName 方法执行业务
child.forEach(Component::editName);
}
}
3、定义文件
/**
* 文件
*/
public class File extends Component{
@Override
public void add(Component component) {
throw new UnsupportedOperationException();
}
@Override
public void remove(Component component) {
throw new UnsupportedOperationException();
}
@Override
public Component getChild(int index) {
throw new UnsupportedOperationException();
}
@Override
public void editName() {
// 具体的名称修改操作
System.out.println("修改文件:" + this);
}
}
4、客户端调用
// 新建一个外层目录
Directory out = new Directory();
// 新建一个内层目录
Directory in = new Directory();
// 外层目录添加文件
out.add(new File());
// 里层目录添加文件
in.add(new File());
in.add(new File());
// 将内层目录放置在外层目录下
out.add(in);
// 修改文件名
out.editName();
执行结果为:
修改文件:cn.codesail.composite.File@311d617d
修改文件:cn.codesail.composite.File@7c53a9eb
修改文件:cn.codesail.composite.File@ed17bee
可以看到对最外层目录进行操作后,会递归向下处理当前目录和子目录中所有的文件。
优缺点
优点
1、高层模块调用简单。
2、节点自由增加。
缺点
在使用组合模式时,其叶子和树枝的声明都是实现类,而不是接口,违反了依赖倒置原则。
使用场景
部分、整体场景,如树形菜单,文件、文件夹的管理。
注意事项
定义时为具体类。
参考
https://www.bilibili.com/video/BV1u3411P7Na?p=16&vd_source=299f4bc123b19e7d6f66fefd8f124a03
天河有尽身作涯,星海无边前是岸。