【JS设计模式】组合模式

组合模式的使用场景非常明确:

  1. 你想表示对象的部分-整体层次结构时;
  2. 你希望用户忽略组合对象和单个对象的不同,用户将统一地使用组合结构中的所有对象(方法)


组合模式(Composite Pattern)

组合模式,将对象组合成树形结构以表示“部分-整体”的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性。
有时候又叫做部分-整体模式,它使我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以像处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。
组合模式让你可以优化处理递归或分级数据结构。有许多关于分级数据结构的例子,使得组合模式非常有用武之地。关于分级数据结构的一个普遍性的例子是你每次使用电脑时所遇到的:文件系统。文件系统由目录和文件组成。每个目录都可以装内容。目录的内容可以是文件,也可以是目录。按照这种方式,计算机的文件系统就是以递归结构来组织的。如果你想要描述这样的数据结构,那么你可以使用组合模式Composite。

涉及角色

1.Component 是组合中的对象声明接口,在适当的情况下,实现所有类共有接口的默认行为。声明一个接口用于访问和管理Component子部件。
2.Leaf 在组合中表示叶子结点对象,叶子结点没有子结点。
3.Composite 定义有枝节点行为,用来存储子部件,在Component接口中实现与子部件有关操作,如增加(add)和删除(remove)等。

适用性

以下情况下适用Composite模式:
1.你想表示对象的部分-整体层次结构
2.你希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。

//组合接口
      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("该方法必须重写!");
      };
      //菜单中的每一项
      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");
      };
      // 菜单列表
      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;
        }
      };
      // 菜单名称
      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();
      };


//-----------------------------Client-------------------------------------------
      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("---------------------------------------------");




你可能感兴趣的:(【JS设计模式】组合模式)