结构型模式:组合模式
简介
组合模式它本身是一种树形结构模式,可以将其理解为一棵树,其中树为根节点,然后有树枝和树叶,树枝不断的分叉,树枝上也会有树叶。
我们看个图:
它是一种将对象组合成树状的层次结构的模式,用来表示“整体-部分”的关系,使用户对单个对象和组合对象具有一致的访问性。
其实说人话就是,我定义了一个接口,它有一个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();
如果代码不明白可以看下这个类图:
本文系作者 @木灵鱼儿 原创发布在木灵鱼儿站点。未经许可,禁止转载。
暂无评论数据