DesignPattern - 组合模式【结构型】
# 一、组合模式介绍
组合模式又叫部分整体模式,将对象组合成树形结构以表示“部分-整体”的层次结构,可以更好的实现管理操作;组合模式使得用户可以使用一致的方法操作单个对象和组合对象;部分-整体对象的基本操作多数是一样的,但是也有不一样的地方。
本质:组合模式可以使用一棵树来表示
核心组成
- 组合中的对象声明接口(Component):在适当的情况下,实现所有类共有接口的默认行为。声明一个接口用于访问和管理 Component 子部件。
- 容器对象(Composite):定义有枝节点行为,用来存储子部件,在 Component 接口中实现与子部件有关的操作,如增加和删除等。
- 叶子对象(Leaf):没有子节点。
注意:容器对象和叶子节点都实现 Component 接口,这也是能够将两者一致对待的关键所在。
应用场景
- 银行总行,总行有前台、后勤、网络部门等,辖区下还有地方分行,也有前台、后勤、网络部门,最小的分行就没有子分行了
- 公司也是,总公司下有子公司,每个公司大部分的部门都类似
- 文件夹和文件,也有层级管理关系
何时使用
- 当想表达对象的部分-整体的层次结构
- 当我们要处理的对象可以生成一颗树形结构,对树上节点和叶子进行操作时,它能够提供一致的方式,而不用考虑它是节点还是叶子
优点
- 客户只需要面对一致的对象而不用考虑整体部分或者节点叶子
- 方便创建出复杂的层次结构
缺点
- 客户端需要花更多时间理清类之间的层次关系
# 二、组合模式代码实现
以 "文件-文件夹" 为例,在 Linux 系统中,两者均是文件,定义一个文件接口:
说明 :Component 接口定义一些通用属性及方法(还可以增加一些默认行为),故使用抽象类。除了
display()
方法以外,还可以定义诸如rename()
、delete()
等 文件 和 文件夹 都可以有的方法,当然这类方法对于文件和文件夹而言是不一样的,文件的 delete() 是删除自己,而文件夹的 delete() 则可以是删除整个文件目录。
/**
* 组合中的对象声明接口(声明一个接口用于访问和管理子部件)
*
* @author GitLqr
*/
public abstract class File {
String name;
public File(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/**
* 显示子部件信息
*/
public abstract void display();
}
定义容器对象(文件夹)类:
说明 :因为是容器对象,需要定义容器(一般是数组)来存储子部件,以及增加必要的管理子部件的方法,如:增加、删除。
/**
* 容器对象(定义枝节点行为,存储子部件):文件夹
*
* @author GitLqr
*/
public class Folder extends File {
private List<File> files = new ArrayList<>();
public Folder(String name) {
super(name);
}
/**
* 浏览文件夹中的文件
*/
@Override
public void display() {
for (File file : files) {
file.display();
}
}
/**
* 向文件夹中添加文件
*/
public void addFile(File file) {
files.add(file);
}
/**
* 从文件夹中删除文件
*/
public void removeFile(File file) {
files.remove(file);
}
}
定义叶子对象(具体文件)类:
说明:叶子对象没有子节点,所以不需要像文件夹那样,只需要实现 Component 接口中的方法即可。
/**
* 叶子节点:文本文件
*
* @author GitLqr
*/
public class TextFile extends File {
public TextFile(String name) {
super(name);
}
@Override
public void display() {
System.out.println("文本文件 - 文件名为:" + name);
}
}
/**
* 叶子节点:图像文件
*
* @author GitLqr
*/
public class ImageFile extends File {
public ImageFile(String name) {
super(name);
}
@Override
public void display() {
System.out.println("图像文件,文件名:" + name);
}
}
使用:
说明:
display()
方法对于文件夹【容器对象】而言,是显示容器中所有 "文件" 的信息,对于具体文件【叶子对象】而言,则是显示自己的信息。
public static void main(String[] args) {
Folder folder1 = new Folder("文件夹1");
// 填充文件夹2
Folder folder2 = new Folder("文件夹2");
TextFile readmeFile = new TextFile("readme.txt");
ImageFile qrcodeFile = new ImageFile("qrcode.jpg");
ImageFile pictureFile = new ImageFile("picture.jpg");
folder2.addFile(readmeFile);
folder2.addFile(qrcodeFile);
folder2.addFile(pictureFile);
// 把文件夹2添加到文件夹1中
folder1.addFile(folder2);
// "递归"遍历文件夹1中所有的文件
folder1.display();
}
- 01
- Flutter - 危!3.24版本苹果审核被拒!11-13
- 02
- Flutter - 轻松搞定炫酷视差(Parallax)效果09-21
- 03
- Flutter - 轻松实现PageView卡片偏移效果09-08