什么是宏命令
- 宏命令是一组命令的集合,通过执行宏命令的方式,可以依次执行一批命令。
例子
const closeDoorCommand = {
execute() {
console.log('关门')
}
}
const openPCCommand = {
execute() {
console.log('开电脑')
}
}
const openQQCommand = {
execute() {
console.log('登陆QQ')
}
}
class MacroCommand {
constructor() {
this.commandList = []
}
add(command) {
this.commandList.push(command)
}
execute() {
this.commandList.map(cmd => cmd.execute())
}
}
// 创建宏命令
const macroCommand = new MacroCommand()
// 添加子命令
macroCommand.add(closeDoorCommand)
macroCommand.add(openPCCommand)
macroCommand.add(openQQCommand)
// 执行宏命令
macroCommand.excute()
什么是组合模式
- 在上述宏命令例子中,macroCommand被称为组合对象,而closeDoorCommand、openPCCommand、openQQCommand都是叶对象
- 而组合模式就是用小的对象来构建大的对象,而这些小对象本身也许是由更小的孙对象构成的。
- 将对象组合成树形结构,以表示“部分-整体”的层次结构。
- 并且我们只需要组合对象和单个对象拥有统一的可执行方法(execute),利用对象多态性统一对待组合对象和单个对象,使客户端忽略组合对象和单个对象的不同,在上述例子中,我们添加命令时不需要关注添加的命令是宏命令还是普通的子命令
例子
export class Folder {
constructor(name) {
this.name = name
this.parent = null;
this.files = []
}
add(file) {
file.parent = this;
this.files.push(file)
}
scan() {
console.log('开始扫描文件夹'+ this.name)
this.files.map(f => {
f.scan()
})
}
remove() {
if (!this.parent) { // 根结点或者树外的游离节点
return
}
this.parent.files.map((file, index) => {
if (file === this) {
this.parent.files.splice(index, 1)
}
})
}
}
export class File {
constructor(name) {
this.name = name
this.parent = null
}
add() {
throw new Error('文件夹下不能添加问津啊')
}
scan() {
console.log('开始扫描文件:' + this.name + '-' + this.parent.name)
}
remove() {
if (!this.parent) { // 根结点或者树外的游离节点
return
}
this.parent.files.map((file, index) => {
if (file === this) {
this.parent.files.splice(index, 1)
}
})
}
}
// 现有的文件目录
export const folder = new Folder('学习资料')
const folder1 = new Folder('JS')
const folder2 = new Folder('JQ')
const file1 = new File('js设计模式')
const file2 = new File('精通JQ')
const file3 = new File('重构与模式')
folder1.add(file1)
folder2.add(file2)
folder.add(folder1)
folder.add(folder2)
folder.add(file3)
//移动硬盘的文件目录
const folder3 = new Folder('node.js')
const file4 = new File('深入浅出node')
folder3.add(file4)
const file5 = new File('js语言精髓')
// 将移动硬盘的文件复制到现有目录中
folder.add(folder3)
folder.add(file5)
// 扫描
folder.scan()
// 移除js语言精髓 以及 精通JQ文件夹
file5.remove()
folder2.remove()
// 移除后扫描
console.log('-------------remove---------------')
folder.scan()
结果如下
需要注意的地方
- 组合模式不是父子关系,所以我们例子中复制是直接复制到该层文件夹
- 对叶对象操作的一致性,组合模式除了要求组合对象和叶对象拥有相同的接口之外,还有一个必要条件,就是对一组对象的操作必须具有一致性,就是该操纵对待列表中的每个叶对象都需要是一致执行的。
- 叶对象和组合对象之间是完全的单映射关系,不存在双向映射关系,即叶对象只和其中一个组合对象保持映射关系
- 用职责链模式提高组合模式性能,当节点较多时,遍历树的过程中,性能方面可能不够理想,这个时候我们可以借助职责链模式去提高性能。