之前写Python的时候,用到了装饰器,然后不由自主想到了设计模式中的装饰模式,正好最近一直在看设计模式,就记录下自己的一些理解。如有错误,欢迎指正。
装饰模式
比较官方的定义是这样的
装饰模式是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象
装饰,装饰嘛,很显然你只想让别人看见最终装饰的东西,并不像让别人看见你的装饰过程。打个比方说,你去餐馆吃饭,很明显主要是吃饭,当然光吃米饭,肯定难以下咽了,你想了想准备吃青椒肉丝盖浇饭,然后餐馆厨房开始做了,这个时候你想去厨房去瞧一瞧,你发现厨房门上贴着“非工作人员入内”,意思很明显嘛,餐馆并不希望我去参观他做盖浇饭的过程,谁知道中间有什么猫腻,最后呈现在我面前的就是我自己点的那份青椒肉丝盖浇饭,当然盖浇饭不止这一种还有番茄鸡蛋盖浇饭啊,鱼香肉丝盖浇饭啊。。。不过厨房加工的地方不让看。
类图是这样的:
可以把Component看作一个食物,ConcreteComponent看作米饭,Decorator则可以看作加工过程,ConcreteDecoratorA(B)就是各种食物素材啦。
对于Componet是无需知道Decorator存在的。
如果只有一个ConcreteComponent类而没有抽象的Component类,那么Decorator类可以是ConcreteComponent的一个子类。同样如果只有一个ConcreteDecorator
,那么也没有必要建立一个单独的Decorator,而可以把Decorator和ConcreteDecorator的责任合并成一个类。
这个时候的类图,如下:
和这样
顺便说下starUML类图中部分符号的含义:
- 类 ( Class ) :三层矩形框表示,第一层类名,如果是抽象类,是用斜体表示的;第二层是字段和属性;第三层则是类方法,其中”+”表示该方法是public的,“-”表示private,“#”表示protected
- 继承类():用空心三角形+实现来表示
Talk is cheap,show me the code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
| <?php abstract class food { public $_name; abstract public function cook(); }
class rice extends food { public function __construct() { $this->_name = 'rice'; }
public function cook() { return "cooked_rice"; } }
class fooddecorator extends food { public function __construct() { $this->_name = 'fooddecorator'; }
public function cook(){ return "cooking"; } }
class capsicum extends fooddecorator { public $_food; public function __construct($food) { $this->_name = 'capsicum'; if($food instanceof food) { $this->_food = $food; }else{ return false; } }
public function cook() { return $this->_food->cook()." cooked_capsicum"; } }
class meat extends fooddecorator { public $_food; public function __construct($food) { $this->_name = 'meat'; if($food instanceof food) { $this->_food = $food; }else{ return false; } }
public function cook() { return $this->_food->cook()." cooked_meat"; } }
$rice = new rice();
$qr = new capsicum($rice);
$qjrs = new meat($qr);
echo "fried green peppers:".$qjrs->cook(); ?>
|
结果:
好像忘记加盐了0.0
装饰模式是围绕一个核心,然后动态装饰这个核心,很明显盖浇饭的核心是饭,在饭上加不同的菜,产生了不同的盖浇饭
这个时候估计有人说了,我不用装饰模式也可以实现着个过程啊
然后写了这样的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| <?php abstract class food { public $_name; abstract public function cook(); }
class rice extends food { public function __construct() { $this->_name = 'rice'; }
public function cook() { return " cooked_rice"; } }
class capsicum extends food { public function __construct() { $this->_name = 'capsicum'; }
public function cook() { return " cooked_capsicum"; } }
class meat extends food { public function __construct() { $this->_name = 'meat'; }
public function cook() { return " cooked_meat"; } }
$rice = new rice(); $capsicum = new capsicum(); $meat = new meat(); echo "fried green peppers:".$rice->cook().$capsicum->cook().$meat->cook(); ?>
|
结果很明显跟上面一样但是没有区别吗很明显第二种方法,第二种方法暴露了你做盖浇饭的顺序,就相当于顾客悄悄溜进厨房,看着厨师把盖浇饭做好了,见证了这一从无到有的过程,因此我们需要用装饰模式,将这加工处理的工程隐藏起来,只有这一个区别吗?很明显并不是,第二种方法三个子类处于同级,不分主次,但是不要忘了,顾客是去吃米饭的,之所以要了盖浇饭是为了让米饭更好吃,如果真的没有菜,做不成盖浇饭,只吃米顾客还是可以接受的,但是要是没有米,光有菜可不行,米饭是前提条件。要是觉得难以接受这个设定,就把盖浇饭换成各种类型的粥吧,绿豆粥,红薯粥。。。,要是少了米,还能叫粥吗。
最后做下简单的总结
装饰模式总结
1.装饰模式是向原有的类,动态的添加新的功能。
2.把类中的装饰功能从类中移去,是简化了原有类。
3.跟继承的区别,装饰模式是围绕着一个核心,在该核心存在的情况下去进行的,存在主次的关系,而继承所有子类处于同级
4.装饰模式的装饰顺序也是很重要,继承则不存在这种问题。比如说,穿衣服,你应该先穿内衣,再穿外套,而不是任意顺序。
5.多用组合,少用继承