工厂模式告一段落,咱们来钻研其余一些模式。不晓得各位大佬有没有尝试过女装?据说女装大佬程序员很多哟。其实,明天的装璜器模式就和化妆这件事很像。置信如果有程序媛MM在的话,马上就能和你讲清楚这个设计模式。
Gof类图及解释
装璜这两个字,咱们暂且把他变成化妆。首先你得有一张脸,而后打底,而后上妆,能够早上来个淡妆下班,也能够上班的时候补成浓妆进来嗨。当然,码农们上班的工夫点正好是能赶上早场的下半场的。话说回来,不管怎么化妆,你的脸还是你的脸,有可能能够化成他人不意识的另一个人,但这的的确确还是你的脸。这就是装璜器,对对象(脸)进行各种装璜(化妆),让这个脸更好看(减少职责)。
GoF定义:动静地给一个对象增加一些额定的职责,就减少性能来说,Decorator模式相比生成子类更为灵便
GoF类图
代码实现
interface Component{ public function operation();}class ConcreteComponent implements Component{ public function operation(){ echo "I'm face!" . PHP_EOL; }}
很简略的一个接口和一个实现,这里咱们就把具体的实现类看作是一张脸吧!
abstract class Decorator implements Component{ protected $component; public function __construct(Component $component){ $this->component = $component; }}
形象的装璜者类,实现Component接口,但并不实现operation()办法,让子类去实现。在这里次要保留一个Componet的援用,一会就要对他进行装璜。对应到上方的具体类,咱们就是要筹备给脸化妆啦!
class ConcreteDecoratorA extends Decorator{ public $addedState = 1; // 没什么实际意义的属性,只是区别于ConcreteDecoratorB public function operation(){ echo $this->component->operation() . "Push " . $this->addedState . " cream!" . PHP_EOL; }}class ConcreteDecoratorB extends Decorator{ public function operation(){ $this->component->operation(); $this->addedBehavior(); } // 没什么实际意义的办法,只是区别于ConcreteDecoratorA public function addedBehavior(){ echo "Push 2 cream!" . PHP_EOL; }}
两个具体装璜者。在这里我是涂了两次霜,毕竟是纯爷们,对化妆这事儿真的是不理解。如同第一步应该先是打粉底吧?不过这次就这样,咱们这两个装璜器实现的就是给脸上涂两层霜。
- 从代码中能够看出,咱们是始终对具体的那个ConcreteComponent对象来进行包装
- 再往下的话其实咱们是对他的operation()这个办法包装了两次,每次都是在前一次的根底上加了一点点货色
- 不要纠结于A和B装璜器上的added属性和办法,他们只是GoF类图中用以区别这两个装璜器不是同一个货色,每个装璜器都能够干很多别的事,Component对象也不肯定只有operation()这一个办法,咱们能够选择性的去装璜对象中的全副或者局部办法
- 如同咱们都继承了Component,间接子类一路重写不就行了,搞这吃力干嘛?亲,理解下组合的概念哟,咱们的Decorator父类外面是一个实在对象的援用哦,解耦了本身哦,咱们只给实在的对象去做包装,您可别间接实例化装璜器来间接用
- 还是没懂?益处呢?老零碎的类啊、办法啊你敢轻易乱改?想给后任写的牛(S)逼(B)代码扩大新性能时无妨试试装璜器这货,说不定有奇效!
手机这玩意干不过某米、某O、某为,这没法玩呀,好吧,哥们去分心做手机壳吧!嗯,我先筹备了一个通明壳(Component),貌似有点丑,没方法,谁叫哥们穷。给某米的加上各种纯色(DecoratorA1),而后背地印上各种色彩的动物(DecoratorB1)吧;某O的手机最近喜爱找流量显著做代言,那我给他的手机壳就用各种炫黑白(DecoratorA2)和明星的卡通头像(DecoratorB2);最初的某为,如同手机曾经开始引领业界潮流了,折叠屏这玩意不是要砸我这卖手机壳的生意嘛!!好吧,哥不给你们做了,还是跟我的某米、某O混去吧!!
残缺代码:装璜器模式
实例
持续来发短信,之前咱们用工厂模式解决了多个短信运营商的问题。这回咱们要解决的是短信内容模板的问题。对于推广类的短信来说,依据最新的广告法,咱们是不能呈现“全国第一”、“全世界第一”这类的词语的,当然,一些不太文化的用语咱们也是不能应用的。
当初的状况是这样的,咱们有一个很早之前的短信模板类,外面的内容是固定的,老零碎仍然还是应用这个模板,老零碎是面对的外部员工,对语言内容的要求不高。而新零碎则须要向全网发送,也就是内外部的用户都要发送。这时,咱们能够用装璜器模式来对老零碎的短信模板进行包装。其实说简略点,咱们就是用装璜器来做文本替换的性能。益处呢?当然是能够不去改变原来的模板类中的办法就实现了对老模板内容的批改扩大等。
短信发送类图
残缺源码:短信发送装璜器办法
<?php// 短信模板接口interface MessageTemplate{ public function message();}// 假如有很多模板实现了下面的短信模板接口// 上面这个是其中一个优惠券发送的模板实现class CouponMessageTemplate implements MessageTemplate{ public function message() { return '优惠券信息:咱们是全国第一的牛X产品哦,送您十张优惠券!'; }}// 咱们来筹备好装璜下面那个过期的短信模板abstract class DecoratorMessageTemplate implements MessageTemplate{ public $template; public function __construct($template) { $this->template = $template; }}// 过滤新广告法中不容许呈现的词汇class AdFilterDecoratorMessage extends DecoratorMessageTemplate{ public function message() { return str_replace('全国第一', '全国第二', $this->template->message()); }}// 应用咱们的大数据部门共事主动生成的新词库来过滤敏感词汇,这块过滤不是强制要过滤的内容,可抉择应用class SensitiveFilterDecoratorMessage extends DecoratorMessageTemplate{ public $bigDataFilterWords = ['牛X']; public $bigDataReplaceWords = ['好用']; public function message() { return str_replace($this->bigDataFilterWords, $this->bigDataReplaceWords, $this->template->message()); }}// 客户端,发送接口,须要应用模板来进行短信发送class Message{ public $msgType = 'old'; public function send(MessageTemplate $mt) { // 发送进来咯 if ($this->msgType == 'old') { echo '面向内网用户发送' . $mt->message() . PHP_EOL; } else if ($this->msgType == 'new') { echo '面向全网用户发送' . $mt->message() . PHP_EOL; } }}$template = new CouponMessageTemplate();$message = new Message();// 老零碎,用不着过滤,只有外部用户才看失去$message->send($template);// 新零碎,面向全网公布的,须要过滤一下内容哦$message->msgType = 'new';$template = new AdFilterDecoratorMessage($template);$template = new SensitiveFilterDecoratorMessage($template);// 过滤完了,发送吧$message->send($template);
阐明
- 装璜器的最大益处:一是不扭转原有代码的状况下对原有代码中的内容进行扩大,凋谢关闭准则;二是每个装璜器实现本人的性能,繁多职责;三是用组合实现了继承的感觉;
- 最实用于:给老零碎进行扩大
- 要小心:过多的装璜者会把你搞晕的
- 不肯定都是对同一个办法进行装璜,其实装璜者应该更多的用于对对象的装璜,对对象进行扩大,这里咱们都是针对一个办法的输入进行装璜,但仅限此文,装璜器的利用其实更加宽泛
- 装璜器的特点是全副都继承自一个主接口或类,这样的益处就是返回的对象是雷同的形象数据,具备雷同的行为属性,否则,就不是装璜之前的对象,而是一个新对象了
- 有点不好了解没关系,咱们这次的例子其实也很勉强,这个设计模式在《Head First设计模式》中有提到Java的I/O系列接口是应用的这种设计模式:FileInputStream、LineNumberInputStream、BufferInputStream等
- Laravel框架中的中间件管道,这里其实是多种模式的综合利用,其中也利用到了装璜器模式:[Laravel HTTP——Pipeline 中间件装璜者模式源码剖析
](https://learnku.com/articles/...
- 另外在Laravel中,日志解决这里也是对Monolog进行了装璜,有趣味的同学能够去理解下
下期看点
又是大伽驾到,电源适配器理解吧?变压器总见过吧?你可能用过,也可能没用过,但你肯定据说过这个十分十分闻名的适配器模式。
各自媒体平台均可搜寻【硬核项目经理】