概述
- 定义 : 将对象组合成树形结构以表示"部分-整体"的层次结构
- 组合模式使客户端对单个对象和组合对象保持一致的方式处理
- 类型 : 结构型
适用场景
- 希望客户端可以忽略组合对象与单个对象的差异时
- 处理一个树形结构时
优点
- 清楚地定义分层次的复杂对象, 表示对象的全部或部分层次
- 让客户端忽略了层次的差异, 方便对整个层次结构进行控制
- 简化客户端代码
- 符合开闭原则
缺点
- 限制类型时会较为复杂
- 使设计变得更加抽象
模式角色
-
Component
-
为组合中的对象声明接口。
-
在适当的情况下,实现所有类共有接口的缺省行为。
-
声明一个接口用于访问和管理C o m p o n e n t的子组件。
-
(可选)在递归结构中定义一个接口,用于访问一个父部件,并在合适的情况下实现它。
-
-
Leaf
-
在组合中表示叶节点对象,叶节点没有子节点。
-
在组合中定义图元对象的行为。
-
-
Composite
-
定义有子部件的那些部件的行为。
-
存储子部件。
-
在Component接口中实现与子部件有关的操作。
-
-
Client : 通过Component接口操纵组合部件的对象。
代码实现
场景
以最常见的操作文件和文件夹为例, 定义如下几个类
- FileComponent类, 对应Component角色
- File类,对应Leaf角色
- Catalog类, 对应Composite角色
- Client 测试类, 对应Client角色
UML类图
代码实现
import java.util.List;
/**
* @author 七夜雪
* @create 2018-11-23 19:44
*/
public abstract class FileComponent {
public void addFile(FileComponent file){
throw new UnsupportedOperationException("不支持新增文件操作");
}
public void removeFile(FileComponent file){
throw new UnsupportedOperationException("不支持删除文件操作");
}
public int getSize(){
throw new UnsupportedOperationException("不支持获取文件列表操作");
}
public String getName(){
throw new UnsupportedOperationException("不支持获取文件名称操作");
}
// 打印文件列表或者文件名称
public void print(){
throw new UnsupportedOperationException("不支持打印文件操作");
}
public List<FileComponent> getFileList(){
throw new UnsupportedOperationException("不支持获取文件列表操作");
}
}
/**
* 对应模式中Leaf角色
*
* @author 七夜雪
* @create 2018-11-23 19:50
*/
public class File extends FileComponent {
private String name;
private int size;
public File(String name, int size) {
this.name = name;
this.size = size;
}
@Override
public int getSize() {
return this.size;
}
@Override
public String getName() {
return this.name;
}
@Override
public void print() {
System.out.println("文件名称 : " + this.name + " 文件大小 : " + this.size + "KB");
}
}
/**
* 目录类, 对应模式中Composite
*
* @author 七夜雪
* @create 2018-11-23 19:54
*/
public class Catalog extends FileComponent {
private String name;
private Integer level;
private List<FileComponent> list = new ArrayList<>();
public Catalog(String name, Integer level) {
this.name = name;
this.level = level;
}
@Override
public void addFile(FileComponent file) {
list.add(file);
}
@Override
public void removeFile(FileComponent file) {
list.remove(file);
}
@Override
public String getName() {
return this.name;
}
@Override
public void print() {
System.out.println(this.name);
for (FileComponent fileComponent : list) {
String space = "";
if (level != null) {
for (Integer i = 0; i < level; i++) {
space += " ";
}
}
System.out.print(space);
fileComponent.print();
}
}
}
测试类 :
public static void main(String[] args) {
FileComponent catlog = new Catalog("D:/", 1);
FileComponent catlog1 = new Catalog("小说", 2);
FileComponent catlog2 = new Catalog("电影", 2);
catlog.addFile(catlog1);
catlog.addFile(catlog2);
FileComponent file1 = new File("傲慢与偏见", 150);
FileComponent file2 = new File("基督山伯爵", 1024);
catlog1.addFile(file1);
catlog1.addFile(file2);
FileComponent file3 = new File("复仇者联盟", 2048 * 1024);
FileComponent file4 = new File("战狼", 1024 * 1024);
catlog2.addFile(file3);
catlog2.addFile(file4);
catlog.print();
}
测试结果:
D:/
小说
文件名称 : 傲慢与偏见 文件大小 : 150KB
文件名称 : 基督山伯爵 文件大小 : 1024KB
电影
文件名称 : 复仇者联盟 文件大小 : 2097152KB
文件名称 : 战狼 文件大小 : 1048576KB
本文参考:
慕课网<java设计模式精讲 Debug 方式+内存分析>课程
四人帮<设计模式>