<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12
      代碼改變世界

      深入理解JavaScript系列(40):設計模式之組合模式

      2012-04-12 08:35  湯姆大叔  閱讀(13199)  評論(12)    收藏  舉報

      介紹

      組合模式(Composite)將對象組合成樹形結構以表示“部分-整體”的層次結構,組合模式使得用戶對單個對象和組合對象的使用具有一致性。

      常見的場景有asp.net里的控件機制(即control里可以包含子control,可以遞歸操作、添加、刪除子control),類似的還有DOM的機制,一個DOM節點可以包含子節點,不管是父節點還是子節點都有添加、刪除、遍歷子節點的通用功能。所以說組合模式的關鍵是要有一個抽象類,它既可以表示子元素,又可以表示父元素。

      正文

      舉個例子,有家餐廳提供了各種各樣的菜品,每個餐桌都有一本菜單,菜單上列出了該餐廳所偶的菜品,有早餐糕點、午餐、晚餐等等,每個餐都有各種各樣的菜單項,假設不管是菜單項還是整個菜單都應該是可以打印的,而且可以添加子項,比如午餐可以添加新菜品,而菜單項咖啡也可以添加糖啊什么的。

      這種情況,我們就可以利用組合的方式將這些內容表示為層次結構了。我們來逐一分解一下我們的實現步驟。

      第一步,先實現我們的“抽象類”函數MenuComponent:

      var MenuComponent = function () {
      };
      MenuComponent.prototype.getName = function () {
      throw new Error("該方法必須重寫!");
      };
      MenuComponent.prototype.getDescription = function () {
      throw new Error("該方法必須重寫!");
      };
      MenuComponent.prototype.getPrice = function () {
      throw new Error("該方法必須重寫!");
      };
      MenuComponent.prototype.isVegetarian = function () {
      throw new Error("該方法必須重寫!");
      };
      MenuComponent.prototype.print = function () {
      throw new Error("該方法必須重寫!");
      };
      MenuComponent.prototype.add = function () {
      throw new Error("該方法必須重寫!");
      };
      MenuComponent.prototype.remove = function () {
      throw new Error("該方法必須重寫!");
      };
      MenuComponent.prototype.getChild = function () {
      throw new Error("該方法必須重寫!");
      };

      該函數提供了2種類型的方法,一種是獲取信息的,比如價格,名稱等,另外一種是通用操作方法,比如打印、添加、刪除、獲取子菜單。

      第二步,創建基本的菜品項:

      var MenuItem = function (sName, sDescription, bVegetarian, nPrice) {
      MenuComponent.apply(this);
      this.sName = sName;
      this.sDescription = sDescription;
      this.bVegetarian = bVegetarian;
      this.nPrice = nPrice;
      };
      MenuItem.prototype = new MenuComponent();
      MenuItem.prototype.getName = function () {
      return this.sName;
      };
      MenuItem.prototype.getDescription = function () {
      return this.sDescription;
      };
      MenuItem.prototype.getPrice = function () {
      return this.nPrice;
      };
      MenuItem.prototype.isVegetarian = function () {
      return this.bVegetarian;
      };
      MenuItem.prototype.print = function () {
      console.log(this.getName() + ": " + this.getDescription() + ", " + this.getPrice() + "euros");
      };

      由代碼可以看出,我們只重新了原型的4個獲取信息的方法和print方法,沒有重載其它3個操作方法,因為基本菜品不包含添加、刪除、獲取子菜品的方式。

      第三步,創建菜品:

      var Menu = function (sName, sDescription) {
      MenuComponent.apply(this);
      this.aMenuComponents = [];
      this.sName = sName;
      this.sDescription = sDescription;
      this.createIterator = function () {
      throw new Error("This method must be overwritten!");
      };
      };
      Menu.prototype = new MenuComponent();
      Menu.prototype.add = function (oMenuComponent) {
      // 添加子菜品
      this.aMenuComponents.push(oMenuComponent);
      };
      Menu.prototype.remove = function (oMenuComponent) {
      // 刪除子菜品
      var aMenuItems = [];
      var nMenuItem = 0;
      var nLenMenuItems = this.aMenuComponents.length;
      var oItem = null;

      for (; nMenuItem < nLenMenuItems; ) {
      oItem = this.aMenuComponents[nMenuItem];
      if (oItem !== oMenuComponent) {
      aMenuItems.push(oItem);
      }
      nMenuItem = nMenuItem + 1;
      }
      this.aMenuComponents = aMenuItems;
      };
      Menu.prototype.getChild = function (nIndex) {
      //獲取指定的子菜品
      return this.aMenuComponents[nIndex];
      };
      Menu.prototype.getName = function () {
      return this.sName;
      };
      Menu.prototype.getDescription = function () {
      return this.sDescription;
      };
      Menu.prototype.print = function () {
      // 打印當前菜品以及所有的子菜品
      console.log(this.getName() + ": " + this.getDescription());
      console.log("--------------------------------------------");

      var nMenuComponent = 0;
      var nLenMenuComponents = this.aMenuComponents.length;
      var oMenuComponent = null;

      for (; nMenuComponent < nLenMenuComponents; ) {
      oMenuComponent = this.aMenuComponents[nMenuComponent];
      oMenuComponent.print();
      nMenuComponent = nMenuComponent + 1;
      }
      };

      注意上述代碼,除了實現了添加、刪除、獲取方法外,打印print方法是首先打印當前菜品信息,然后循環遍歷打印所有子菜品信息。

      第四步,創建指定的菜品:

      我們可以創建幾個真實的菜品,比如晚餐、咖啡、糕點等等,其都是用Menu作為其原型,代碼如下:

      var DinnerMenu = function () {
      Menu.apply(this);
      };
      DinnerMenu.prototype = new Menu();

      var CafeMenu = function () {
      Menu.apply(this);
      };
      CafeMenu.prototype = new Menu();

      var PancakeHouseMenu = function () {
      Menu.apply(this);
      };
      PancakeHouseMenu.prototype = new Menu();

      第五步,創建最頂級的菜單容器——菜單本:

      var Mattress = function (aMenus) {
      this.aMenus = aMenus;
      };
      Mattress.prototype.printMenu = function () {
      this.aMenus.print();
      };

      該函數接收一個菜單數組作為參數,并且值提供了printMenu方法用于打印所有的菜單內容。

      第六步,調用方式:

      var oPanCakeHouseMenu = new Menu("Pancake House Menu", "Breakfast");
      var oDinnerMenu = new Menu("Dinner Menu", "Lunch");
      var oCoffeeMenu = new Menu("Cafe Menu", "Dinner");
      var oAllMenus = new Menu("ALL MENUS", "All menus combined");

      oAllMenus.add(oPanCakeHouseMenu);
      oAllMenus.add(oDinnerMenu);

      oDinnerMenu.add(new MenuItem("Pasta", "Spaghetti with Marinara Sauce, and a slice of sourdough bread", true, 3.89));
      oDinnerMenu.add(oCoffeeMenu);

      oCoffeeMenu.add(new MenuItem("Express", "Coffee from machine", false, 0.99));

      var oMattress = new Mattress(oAllMenus);
      console.log("---------------------------------------------");
      oMattress.printMenu();
      console.log("---------------------------------------------");

      熟悉asp.net控件開發的同學,是不是看起來很熟悉?

      總結

      組合模式的使用場景非常明確:

      1. 你想表示對象的部分-整體層次結構時;
      2. 你希望用戶忽略組合對象和單個對象的不同,用戶將統一地使用組合結構中的所有對象(方法)

      另外該模式經常和裝飾者一起使用,它們通常有一個公共的父類(也就是原型),因此裝飾必須支持具有add、remove、getChild操作的 component接口。

      參考:https://github.com/tcorral/Design-Patterns-in-Javascript/blob/master/Composite/index.html

      同步與推薦

      本文已同步至目錄索引:深入理解JavaScript系列

      深入理解JavaScript系列文章,包括了原創,翻譯,轉載等各類型的文章,如果對你有用,請推薦支持一把,給大叔寫作的動力。

      主站蜘蛛池模板: 东兴市| 九九热在线视频精品免费| 天天摸天天操免费播放小视频 | 国产99视频精品免费专区| 亚洲精品一区二区在线播| 久久被窝亚洲精品爽爽爽| 亚洲av无码成人精品区一区| 永久免费无码av在线网站| 97午夜理论电影影院| 亚洲 欧美 清纯 校园 另类| 欧美成人午夜性视频| 日韩中文字幕有码av| 黄网站色视频免费观看| 精品综合一区二区三区四区| 深夜福利资源在线观看| 国产视频最新| 国产私拍福利精品视频| 大地资源免费视频观看| 内射囯产旡码丰满少妇| 久久三级国内外久久三级| 国产av中文字幕精品| 无码福利写真片视频在线播放| 亚洲AV高清一区二区三区尤物| 国产精品久久蜜臀av| 亚洲精品一区久久久久一品av| 日韩精品一区二区在线视| 偷窥盗摄国产在线视频| 国产精品美女一区二三区| 丰满人妻AV无码一区二区三区 | 国产免费久久精品44| 亚洲色欲久久久久综合网| 五月天免费中文字幕av| 天天做天天躁天天躁| 精品久久精品午夜精品久久 | 99精品国产成人一区二区| 亚洲精品一区二区三天美| 亚洲精品沙发午睡系列| 色综合久久天天综线观看| 亚洲色成人一区二区三区人人澡人人妻人人爽人人蜜桃麻豆 | 国产视频深夜在线观看| 亚洲av成人一区在线|