设计模式:装饰者模式

缘由 没什么特别的,之前看懂了,这次自己再复述一下 。毕竟把别人讲懂了才是真的懂了 。主要参考了head first 设计模式 。
书中例子 面和具体的面 例子讲述的是在为星巴克咖啡的制作订单的情况,比如客人点了饮料,那么系统会自动算出价格(不知道是我没有体会到,还是这个例子不太合适,算出价格那么简单的事还需要用到类?,不过不影响我们思考装饰者模式) 。不过似乎星巴克离普通的中国人还是太遥远了,我倒可以认为我们想象成中国面馆比较好 。
这家中国面馆卖很多种类的面,有我喜欢的哨子面、牛肉面、杂酱面、板面等等面,每一个面都有价格,这是非常正常的 。如果每一种面都有一个价格,那么这个订单生成系统好像还比较简单 。因为继承是一种不错的选择 。下图直接截取了head first 设计模式,所以里面是饮料 。那么饮料就相当于我上面所述的面,而牛肉面就相当于一个饮料的一种,比如:Dark Roast 。

设计模式:装饰者模式

文章插图
加了配料的面 问题来了,面还可以加各类配料,比如你说老板多加一个鸡蛋,另一个说多加一个肉丸,多加一个火腿肠 。难道我们为每一种加了配料的面都来实现一种类来计算价钱吗?如此一来,将会有非常多的类 。比如加了鸡蛋的牛肉面、加了肉丸的牛肉面.....那么我们的类就继承就会成为下面这个样子 。
设计模式:装饰者模式

文章插图
可以看出我们要实现每一个子类就非常辛苦了,需要自己懂把加了丸子、鸡蛋的牛肉面,提前加一遍算好放在这个子类里使用 。更可怕的是:如果丸子价格涨了,怎么办?我们又要把所有的有丸子的子类都加一遍吗?
将调料试着实例变量 这是一种可以解决的方案 。在父类面里面有丸子、鸡蛋的布尔值,和具体价格,那么用户在选择添加了鸡蛋的时候,就将鸡蛋的布尔值改为true,然后再将父类的cost()方法实现为加上所有的配料的价格 。那么子类在cost()方法里面用自己这道面的价格加上父类的cost(),就是配料的价格,那么就算出了总共需要多少钱了 。
设计模式:装饰者模式

文章插图
【设计模式:装饰者模式】
设计模式:装饰者模式

文章插图
下图是伪代码,我们可以看出,子类的cost()方面里面调用了父类的cost()方法,而父类cost()方面,主要是判断这个订单有没有加这个某种配料,加了的话就加上这个配料的价格 。
设计模式:装饰者模式

文章插图
然而,这样做有以下三种情况会使我们很难处理:
设计模式:装饰者模式

文章插图
如果出现新调料,我们需要改变超类 。似乎这样很不好某些饮料里面就不能加某些调料,然而我们并没有限制如果某个客户想要双倍的调料,则无法处理 。这里书中: 提出了类应该对扩展开放,对修改关闭 。
因为
引入装饰者模式 此时书中引入装饰者模式,其实我是知道看来了代码之后才知道到底是怎么回事 。我的理解就是,所谓装饰者,其也是继承于基类(面)的一个实现类,这个实现类必须有有有一个成员变量:就是另一个实现类,也就是被包含的实现类,也就是我们装饰者所要装饰的对象 。比如牛肉面就是一个实现类,他是被装饰的,可以被加鸡蛋这个实现类来修饰,加鸡蛋这个实现类的成员变量可以引用牛肉面,那么就组成了加鸡蛋的牛肉面,如果其成员变量引用了哨子面,那么就成了加鸡蛋的哨子面 。而且,这个加鸡蛋的哨子面还可以被加丸子的实现类来装饰,那么就是成了加丸子 加鸡蛋的牛肉面 。当然,也可以加两个鸡蛋 。