Last Surprise Lyn
  1. 1 Last Surprise Lyn
  2. 2 Flower Of Life 发热巫女
  3. 3 かかってこいよ NakamuraEmi
  4. 4 Life Will Change Lyn
  5. 5 Hypocrite Nush
  6. 6 Libertus Chen-U
  7. 7 Time Bomb Veela
  8. 8 BREAK IN TO BREAK OUT Lyn
  9. 9 Warcry mpi
  10. 10 One Last You Jen Bird
2017-06-11 22:49:25

设计模式——组合模式

俗话说无规矩不成方圆。在现实生活中,无论什么团体都会有自己的一套规章制度来管理,就像军队一样,即使人数众多也能在集体活动时保持统一与协调。在程序设计中也是如此,有时候我们可能需要针对一个子元素相似的结构操作数据,这时候组合模式就派上用场了。


组合模式原理

组合模式将相似的对象组合成一个整体树形结构,并且提供一种遍历树形结构的方案。核心思想就是统一部分和整体。利用对象多态性给整体和部分设计相同的接口,刻意使用户忽略组合对象和子对象的不同。这是非常有用的,有点像高中分析受力的整体法,从全局来操控。

举个例子,比如我们现在有一堆形态不一的物体,需要从A搬到B。而这些物体呢有的只能用瓶子装着移动,有的只能抱着移动,分开处理肯定是比较麻烦的。那么我们给他们共同设计一个“推”的接口,将他们全部装入一辆小车。现在我们只用对小车使用推的指令,就可以同时调用这些物体的"推"的接口,方便的运到目的地了。组合模式的核心思想就是如此。

组合模式实例

下面我们就以文件夹操作的实例来具体分析组合模式。文件夹和文件之间的关系应该是非常适合用组合模式的了,因为对用户来说文件夹也是文件。这正是组合模式的要素之一——忽略整体和部分的区别。

let Folder = function(name) {
  this.name = name;
  this.files = [];
};
Folder.prototype.add = function(file) {
    this.files.push(file);
}
Folder.prototype.scan = function() {
  for (let file of this.files) {
    file.scan();
  }
}

let File = function(name) {
  this.name = name;
}
File.prototype.add = function() {
  throw new Error('这不是一个文件夹')
}
File.prototype.scan = function() {
  console.log('开始扫描文件',this.name);
}

可以看到我们特意设计了相同的功能接口,这样当从树结构顶端进行遍历时,就可以忽略叶对象和组合对象间的差异。

进一步改进

通过上例我们实现了组合模式的遍历和增加功能,当然也必须有删除功能。从常理上来说,删除一个节点必然要将它的所有子节点一并删除,一般从它的父节点来切断整体和局部的联系。所以需要明确各个节点之间的父子关系,给所有节点添加相关属性。改进如下:

let Folder = function(name) {
  this.name = name;
  this.parent = null;
  this.files = [];
};
Folder.prototype.add = function(file) {
  file.parent = this;
  this.files.push(file);
};
Folder.prototype.remove = function() {
  if (!this.parent) { // 不是子节点不需要移除
    return;
  }
  for (let file of this.parent.files.entries()) {
    if (file[1] = this) {
      files.splice(file[0], 1);
    }
  }
}

遵循接口相同的思路,file的改动基本也是一致的。

小结

总之在程序设计时,如果感觉可以考虑高中时的所学的整体法来操作,就可以手动统一接口来使用组合模式。当某需求中父子结构本身就有着天然相同的接口,也应该优先考虑组合模式。

-- EOF --

添加在分类「 前端开发 」下,并被添加 「设计模式」 标签。

文章目录

 - [组合模式原理](#组合模式原理)
 - [组合模式实例](#组合模式实例)
 - [进一步改进](#进一步改进)
 - [小结](#小结)
回到首页