简介

组合模式它本身是一种树形结构模式,可以将其理解为一棵树,其中树为根节点,然后有树枝和树叶,树枝不断的分叉,树枝上也会有树叶。

我们看个图:

它是一种将对象组合成树状的层次结构的模式,用来表示“整体-部分”的关系,使用户对单个对象和组合对象具有一致的访问性。

其实说人话就是,我定义了一个接口,它有一个show方法,然后所有的对象都得实现,然后对象之间可以嵌套,因为嵌套了,所以当我调用show方法的时候,这个对象必须去遍历自己的子级嵌套对象的show方法,不断的重复,最终得到结果之和。

类似于一个递归函数,只不过具体的处理都在每个对象自身show方法中去实现。

组合模式常常用在:购物车、节点统计

购物车中最外层是根节点,然后每个店铺为一个树枝,每个商品为一个树叶,他们组合嵌套。

节点统计比如全国的人数统计,我们从:省 ——> 市 ——> 县 ——> 乡;这么一个层级结构,统计时我们只需要调用省的统计方法,它就会触发到市的统计方法,市的统计方法再到县,县再到乡,这样的话我们可以很好的统计的人数,且结构清晰明了,哪怕新增省市或者县乡都不会对原有统计方式破坏性改动,符合开闭原则。

代码实现

//购物车节点的抽象
interface Shopping {
  getPrice(): number; //获取价格
}

//单个商品的具体实现:树叶
class AGoods implements Shopping {
  name = "A商品";
  price = 100;

  getPrice() {
    return this.price;
  }
}

class BGoods implements Shopping {
  name = "A商品";
  price = 70;

  getPrice() {
    return this.price;
  }
}

//店铺的具体实现:树枝
class Store implements Shopping {
  name = "店铺1";
  goodsArr: Array<Shopping> = []; //商品数组

  //添加新商品
  add(goods: Shopping) {
    this.goodsArr.push(goods);
    return this;
  }

  //移除商品
  remove(goods: Shopping) {
    this.goodsArr = this.goodsArr.filter((item) => item !== goods);
  }

  //获取价格
  getPrice() {
    let total = 0;
    this.goodsArr.forEach((item) => {
      total += item.getPrice();
    });
    return total;
  }
}

//购物车:具体使用
class ShoppingCart {
  constructor() {
    //创建一个根节点
    const store = new Store();
    //增加一个店铺
    const d = new Store();

    store.add(d);

    //用户的商品
    const a = new AGoods();
    const b = new BGoods();

    //添加商品
    d.add(a).add(b);

    //获取总价
    console.log(store.getPrice());
  }
}

new ShoppingCart();

代码还是比较简单,意思就是这样,具体的业务逻辑肯定会更加复杂。

因为树枝自身就可以进行嵌套,它可以接受树枝和树叶,所以第一个树枝可以称之为根节点,加上我们遵循Shopping的规则要求都会实现getPrice方法,所以使用的时候没有多余的心智负担,用就完事了。

扩展

上述代码你会发现,树枝的规则要求非常薄弱,我们只是要求的getPrice方法实现,这显然比如后来的人可能约束不到位,所以我们将组合模式扩展一些,这个扩展被称为复杂的组合模式,当然这名称无关紧要,重要的是我们扩展的原因。

实际情况下,树枝和树叶可能各自都有自己的一些具体的方法,这些方法可能需要有,但是没有规则的约束,可能会导致代码的不健全,有的人总是会忘记需要声明对应的方法。

解决办法就是再声明一个树叶和树枝自己的抽象。

商品的抽象

//购物车节点的抽象
interface Shopping {
  getPrice(): number; //获取价格
}

//商品的抽象
abstract class Goods implements Shopping {
  abstract name: string;
  abstract price: number;

  abstract getPrice(): number;
}

//单个商品的具体实现:树叶
class AGoods extends Goods {
  name = "A商品";
  price = 100;

  getPrice() {
    return this.price;
  }
}

class BGoods extends Goods {
  name = "A商品";
  price = 70;

  getPrice() {
    return this.price;
  }
}

店铺的抽象

//店铺的抽象
abstract class Store implements Shopping {
  abstract name: string;
  abstract goodsArr: Array<Shopping>;

  //添加新商品
  add(goods: Shopping) {
    this.goodsArr.push(goods);
    return this;
  }

  //获取价格
  getPrice() {
    let total = 0;
    this.goodsArr.forEach((item) => {
      total += item.getPrice();
    });
    return total;
  }

  //移除商品
  abstract remove(goods: Shopping): void;
}

//店铺的具体实现:树枝
class Stores extends Store {
  name = "店铺1";
  goodsArr: Array<Shopping> = []; //商品数组

  //移除商品
  remove(goods: Shopping) {
    this.goodsArr = this.goodsArr.filter((item) => item !== goods);
  }
}

使用

//购物车:具体使用
class ShoppingCart {
  constructor() {
    //创建一个根节点
    const store = new Stores();
    //增加一个店铺
    const d = new Stores();

    store.add(d);

    //用户的商品
    const a = new AGoods();
    const b = new BGoods();

    //添加商品
    d.add(a).add(b);

    //获取总价
    console.log(store.getPrice());
  }
}

new ShoppingCart();

如果代码不明白可以看下这个类图:

分类: 设计模式 标签: 设计模式结构型模式组合模式树形结构根节点树枝树叶购物车商店商品店铺

评论

暂无评论数据

暂无评论数据

目录