PHP、Python和Javascript的裝飾器模式對(duì)比
修飾模式(Decorator Pattern),又叫裝飾者模式,是面向?qū)ο缶幊填I(lǐng)域中,一種動(dòng)態(tài)地往一個(gè)類中添加新的行為的設(shè)計(jì)模式。就功能而言,修飾模式相比生成子類更為靈活,這樣可以給某個(gè)對(duì)象而不是整個(gè)類添加一些功能。裝飾模式非常適用于靈活擴(kuò)展對(duì)象的功能,下面是裝飾模式的UML圖:
例如,有一個(gè)技術(shù)論壇,用戶通過留言進(jìn)行溝通,由于剛開始論壇里都是熟人,幾乎都不需要對(duì)留言的內(nèi)容作出審核,接收留言的頁(yè)面可以是這樣:
class SaveMsg(){ private $msg; public function __construct($msg){ $this->msg=$msg; } public function __store(){ //存入數(shù)據(jù)庫(kù) } }
后來,隨著論壇逐漸出名,就有一些人在上面發(fā)鏈接,就需要對(duì)含有鏈接的消息進(jìn)行過濾,論壇進(jìn)一步發(fā)展,發(fā)現(xiàn)除開發(fā)垃圾鏈接的外,還有很多無用的灌水,到后來可能還有攻擊等等各種不正常的帖子,所以對(duì)論壇帖子的管理,可以單獨(dú)抽象出一個(gè)類進(jìn)行管理,當(dāng)需要擴(kuò)充過濾規(guī)則時(shí),可以進(jìn)行動(dòng)態(tài)擴(kuò)充。
//基類 abstract class Filter{ abstract public function isForbid(); } //基礎(chǔ)過濾類 class MsgFilter extends Filter{ public $content; public function __construct($msg){ $this->content=$msg; } public function isForbid(){ if(preg_match("/https?/i",$this->content)){ return [true,"Not Allowed Urls"]; }else{ return [false]; } } } //裝飾器,用來擴(kuò)充功能 abstract class FilterDecorator extends Filter{ protected $obj; public function __construct(Filter $obj){ $this->obj=$obj; } } //新過濾器,判斷是否重復(fù)發(fā)帖 class repeat extends FilterDecorator{ public function isForbid(){ if($this->obj->isForbid()[0] === true){ //判定是否包含url return $this->obj->isForbid(); }else if($this->obj->content == "this is a test"){ //判定是否重復(fù)發(fā)帖 return [true,"Repeat Posts"]; }else{ return [false]; } } } $test = new MsgFilter("httpsfdjoafdsajof"); print_r($test->isForbid());//被禁止 $test2 = new repeat(new MsgFilter("this is a test")); print_r($test2->isForbid());//被禁止
在python中,不存在抽象類和方法,實(shí)現(xiàn)就更加簡(jiǎn)單:
#!/usr/bin/env python class Filter(): pass class MsgFilter(Filter): def __init__(self,msg): self.content=msg def isForbid(self): if('http' in self.content): return [True,"Not Allowed Urls"] else: return [False] class FilterDecorator(Filter): def __init__(self,obj): self._obj=obj class Repeat(FilterDecorator): def isForbid(self): if self._obj.isForbid()[0]: return self._obj.isForbid() elif self._obj.content == 'this is a test': return [True,"Repeat Posts"]; else: return [False] test = MsgFilter("this is a content have http urls") print test.isForbid() test2 = Repeat(MsgFilter('this is a test')) print test2.isForbid()
Javascript中,沒有嚴(yán)格的類,所有繼承都基于原型,理解起來會(huì)稍費(fèi)功夫:
function MsgFilter(msg){ this.content=msg; this.isForbid=function(){ if(this.content.match(/http/g)){ return [true,"Not Allowed Urls"]; }else { return [false]; } } } function Repeat(obj){ var _obj=obj; this.isForbid=function(){ if(_obj.isForbid[0] === true){ return _obj.isForbid(); }else if(_obj.content=='this is a test'){ return [true,"Repeat Posts"]; }else{ return [false]; } } } var test = new MsgFilter("his is a content have http urls"); console.log(test.isForbid()); var test2 = new Repeat(new MsgFilter("this is a test")); console.log(test2.isForbid());
由于Javascript缺少類的特性,繼承對(duì)于它來說就顯得有點(diǎn)雞肋了,上面的代碼看起來更像是對(duì)兩個(gè)函數(shù)的處理, 在python中,有更加簡(jiǎn)單的添加裝飾器的方法,直接通過”@”給函數(shù)自動(dòng)添加裝飾器,達(dá)到擴(kuò)展功能的目的,如:
def Decorator(F): def newF(age): print "You Are Calling",F.__name__ F(age) return newF @Decorator #通過@給函數(shù)showAge添加裝飾器Decorator def showAge(age): print "hello , i am %d years old"%age showAge(10)
裝飾模式的目的是解決動(dòng)態(tài)擴(kuò)展功能的難題,裝飾模式的本質(zhì)是對(duì)對(duì)象的靈活處理,理解裝飾模式,不僅能深入了解面向?qū)ο蟮某绦蛟O(shè)計(jì),更能提高編程的思維能力。
相關(guān)文章
PhpStorm本地?cái)帱c(diǎn)調(diào)試的方法步驟
php代碼在調(diào)試時(shí),經(jīng)常是print_r或者var_dump來斷點(diǎn),但是當(dāng)項(xiàng)目較為復(fù)雜的情況下,這么做效率就非常低下了,斷點(diǎn)調(diào)試就非常好的解決了這個(gè)問題,這篇文章主要介紹了PhpStorm本地?cái)帱c(diǎn)調(diào)試的方法步驟,感興趣的小伙伴們可以參考一下2018-05-05ThinkPHP連接數(shù)據(jù)庫(kù)的方式匯總
這篇文章主要介紹了ThinkPHP連接數(shù)據(jù)庫(kù)的方式,包括項(xiàng)目配置文件定義、DSN方式傳參、數(shù)組傳參、模型類里定義等,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2014-12-12php中存儲(chǔ)用戶ID和密碼到mysql數(shù)據(jù)庫(kù)的方法
對(duì)用戶身份驗(yàn)證,最常用的方法就是將用戶id與密碼保存進(jìn)數(shù)據(jù)庫(kù)中了,然后再寫一些登錄檢測(cè)代碼,就可以使用了2013-02-02php+webSoket實(shí)現(xiàn)聊天室示例代碼(附源碼)
本篇文章主要介紹了php+webSoket搭建chatServer示例(附源碼)的資料,這里整理了詳細(xì)的代碼,有需要的小伙伴可以參考下。2017-02-02利用phpexcel把excel導(dǎo)入數(shù)據(jù)庫(kù)和數(shù)據(jù)庫(kù)導(dǎo)出excel實(shí)現(xiàn)
本文介紹利用phpexcel對(duì)數(shù)據(jù)庫(kù)數(shù)據(jù)導(dǎo)入excel(excel篩選)、導(dǎo)出excel,大家參考使用吧2014-01-01關(guān)于PHP中Session文件過多的問題及session文件保存位置
PHP的默認(rèn)機(jī)制:每一次php請(qǐng)求,會(huì)有1/100的概率(默認(rèn)值)觸發(fā)“session回收”。接下來通過本文給大家介紹關(guān)于PHP中Session文件過多的問題及session文件保存位置,需要的朋友參考下2016-03-03