js設計模式–組合模式

aoping發表於2019-02-16

前言

本系列文章主要根據《JavaScript設計模式與開發實踐》整理而來,其中會加入了一些自己的思考。希望對大家有所幫助。

文章系列

js設計模式–單例模式

js設計模式–策略模式

js設計模式–代理模式

js設計模式–迭代器模式

js設計模式–釋出訂閱模式

js設計模式–命令模式

概念

組合模式就是用小的子物件來構建更大的物件,而這些小的子物件本身也許是由更小的“孫物件”構成的。

場景

組合模式除了要求組合物件和葉物件擁有相同的介面之外,還有一個必要條件,就是對一組葉物件的操作必須具有一致性。

優缺點

優點

組合模式將物件組合成樹形結構,以表示“部分-整體”的層次結構。 除了用來表示樹形結 構之外,組合模式的另一個好處是通過物件的多型性表現,使得使用者對單個物件和組合物件的使 用具有一致性

缺點

它可能會產生一個這樣的系統:系統中的每個物件看起來都 與其他物件差不多。它們的區別只有在執行的時候會才會顯現出來,這會使程式碼難以理解。此外, 如果通過組合模式建立了太多的物件,那麼這些物件可能會讓系統負擔不起。

例子

掃描資料夾

這裡把檔案和資料夾無區別對待,檔案和資料夾都具有add和scan方法


var Folder = function (name) {
  this.name = name;
  this.files = [];
};
Folder.prototype.add = function (file) {
  this.files.push(file);
};
Folder.prototype.scan = function () {
  console.log(`開始掃描資料夾: ` + this.name);
  for (var i = 0, file, files = this.files; file = files[i++];) {
    file.scan();
  }
};
/******************************* File ******************************/
var File = function (name) {
  this.name = name;
};
File.prototype.add = function () {
  throw new Error(`檔案下面不能再新增檔案`);
};
File.prototype.scan = function () {
  console.log(`開始掃描檔案: ` + this.name);
};

var folder = new Folder(`學習資料`);
var folder1 = new Folder(`JavaScript`);
var folder2 = new Folder(`jQuery`);
var file1 = new File(`JavaScript 設計模式與開發實踐`);
var file2 = new File(`精通jQuery`);
var file3 = new File(`重構與模式`)
folder1.add(file1);
folder2.add(file2);
folder.add(folder1);
folder.add(folder2);
folder.add(file3);

var folder3 = new Folder(`Nodejs`);
var file4 = new File(`深入淺出Node.js`);
folder3.add(file4);
var file5 = new File(`JavaScript 語言精髓與程式設計實踐`);

folder.add(folder3);
folder.add(file5);

folder.scan();

增加刪除方法

我們需要增加一個父物件的引用


var Folder = function (name) {
  this.name = name;
  this.parent = null; //增加this.parent 屬性
  this.files = [];
};

Folder.prototype.add = function (file) {
  file.parent = this; //設定父物件
  this.files.push(file);
};

Folder.prototype.scan = function () {
  console.log(`開始掃描資料夾: ` + this.name);
  for (var i = 0, file, files = this.files; file = files[i++];) {
    file.scan();
  }
};

Folder.prototype.remove = function () {
  if (!this.parent) { //根節點或者樹外的遊離節點
    return;
  }
  for (var files = this.parent.files, l = files.length - 1; l >= 0; l--) {
    var file = files[l];
    if (file === this) {
      files.splice(l, 1);
    }
  }
};

var File = function (name) {
  this.name = name;
  this.parent = null;
};

File.prototype.add = function () {
  throw new Error(`不能新增在檔案下面`);
};

File.prototype.scan = function () {
  console.log(`開始掃描檔案: ` + this.name);
};

File.prototype.remove = function () {
  if (!this.parent) { //根節點或者樹外的遊離節點
    return;
  }

  for (var files = this.parent.files, l = files.length - 1; l >= 0; l--) {
    var file = files[l];
    if (file === this) {
      files.splice(l, 1);
    }
  }
};

var folder = new Folder(`學習資料`);
var folder1 = new Folder(`JavaScript`);
var file1 = new Folder(`深入淺出Node.js`);

folder1.add(new File(`JavaScript 設計模式與開發實踐`));
folder.add(folder1);
folder.add(file1);
folder1.remove(); //移除資料夾
folder.scan();

相關文章