设计模式读书笔记之组合模式
组合模式
定义
组合模式又称之为部分-整体模式,将对象组合成树形结构,以表示 “部分-整体” 的层次结构。
通过对象的多态性表现,使得用户对单个对象和组合对象的使用具有一致性。
特点
a. 表示 “部分-整体” 的层次结构,生成 "树叶型" 结构;
b. 一致操作性,树叶对象对外接口保存一致;
c.自上而下的的请求流向,从树对象传递给叶对象;
d.调用顶层对象,会自行遍历其下的叶对象执行。
应用场景
命令分发: 只需要通过请求树的最顶层对象,便能对整棵树做统一的操作,在组合模式中增加和删除树的节点非常方便;
统一处理: 统一对待树中的所有对象,忽略组合对象和叶对象的区别;
比如: 文件目录显示,多级目录呈现等树形结构数据的操作。
代码实现
`
// 树对象 - 文件夹
const Tree_Folder = function(folderName) {
return {
folderName: folderName,
folders: [],
add(folder) {
this.folders.push(folder);
},
scan() {
console.log("开始扫描文件夹目录:" + this.folderName);
for (let folder of this.folders) {
folder.scan();
}
}
};
};
//树枝对象 - 子文件夹
const Branch_folder = function(folderName) {
return {
folderName: folderName,
folders: [],
add(folder) {
this.folders.push(folder);
},
scan() {
console.log("开始扫描子文件夹目录:" + this.folderName);
for (let folder of this.folders) {
folder.scan();
}
}
};
};
// 叶对象 - 文件
const Leaf_File = function(fileName) {
return {
fileName: fileName,
add() {
console.log("叶对象中不能添加文件");
},
scan() {
console.log("------:" + this.fileName);
}
};
};
let mediaFolder = Tree_Folder("娱乐(大的组合对象)");
let movieFolder = Branch_folder("电影(小的组合对象)");
let musicFolder = Branch_folder("音乐(小的组合对象)");
let file = Leaf_File("剧本杀(单个对象)");
let file1 = Leaf_File("水浒传.mp4(单个对象)");
let file2 = Leaf_File("红楼梦.mp4(单个对象)");
let file3 = Leaf_File("西游戏.mp4(单个对象)");
let fileA = Leaf_File("再谈记忆.mp3(单个对象)");
let fileB = Leaf_File("光辉岁月.mp3(单个对象)");
let fileC = Leaf_File("海阔天空.mp3(单个对象)");
//将叶对象加入树枝对象中
movieFolder.add(file1);
movieFolder.add(file2);
movieFolder.add(file3);
musicFolder.add(fileA);
musicFolder.add(fileB);
musicFolder.add(fileC);
//将树枝对象或叶对象加入树对象中
mediaFolder.add(file);
mediaFolder.add(movieFolder);
mediaFolder.add(musicFolder);
mediaFolder.scan();
/* 输出:
开始扫描文件夹目录:娱乐(大的组合对象)
------:剧本杀(单个对象)
开始扫描子文件夹目录:电影(小的组合对象)
------:水浒传.mp4(单个对象)
------:红楼梦.mp4(单个对象)
------:西游戏.mp4(单个对象)
开始扫描子文件夹目录:音乐(小的组合对象)
------:再谈记忆.mp3(单个对象)
------:光辉岁月.mp3(单个对象)
------:海阔天空.mp3(单个对象)
*/
`
误区
a. 组合不是继承,树叶对象并不是父子对象
组合模式的树型结构是一种 HAS-A(聚合)的关系,而不是 IS-A(继承)。树叶对象能够合作的关键,是它们对外保持统一接口,而不是叶对象继承树对象的属性方法,两者之间不是父子关系。
b. 叶对象操作保持一致性
叶对象除了与树对象接口一致外,操作也必须保持一致性。一片叶子只能生在一颗树上。调用顶层对象时,每个叶对象只能接收一次请求,一个叶对象不能从属多个树对象。
c.叶对象实现
请求传递由树向叶传递,如果想逆转传递过程,需在叶对象中保留对树对象的引用,冒泡传递给树对象处理。
d. 不只是简单的子集遍历
调用对象的接口方法时,如果该对象是树对象,则会将请求传递给叶对象,由叶对象执行方法,以此类推。不同于迭代器模式,迭代器模式遍历并不会做请求传导。
优缺点
优点:
忽略组合对象和单个对象的差别,对外一致接口使用;
解耦调用者与复杂元素之间的联系,外部调用时无需区分,处理方式变得简单。
缺点:
包裹对象创建太多,额外增加内存负担;
树叶对象接口一致,无法区分,只有在运行时方可辨别。

浙公网安备 33010602011771号