PHP設(shè)計模式(三)-策略模式


layout: post
title: "PHP設(shè)計模式(三)-策略模式"
date: 2016-06-06 10:32:22 +0800
comments: true
categories: [php]


在之前學(xué)習(xí)了PHP設(shè)計模式中的工廠模式,單例模式囱桨,注冊樹模式旺隙,適配器模式每瞒。今天來學(xué)習(xí)一下策略模式稽鞭。

一、策略模式概念

策略模式針對一組算法炼团,將每一個算法封裝到具有共同接口的獨立的類中,此模式讓算法的變化獨立于使用算法的客戶咪惠。從而讓程序結(jié)構(gòu)更靈活击吱,具有更好的擴展性和維護性。

策略模式:定義了算法族,分別封裝起來硝逢,讓它們之間可以互相替換姨拥,此模式讓算法的變化獨立于使用算法的客戶绅喉。

封裝:把行為用接口封裝起來渠鸽,我們可以把那些經(jīng)常變化的部分,從當(dāng)前的類中單獨取出來柴罐,用接口進行單獨的封裝徽缚。
互相替換:我們封裝好了接口,通過指定不同的接口實現(xiàn)類進行算法的變化革屠。

二凿试、策略模式結(jié)構(gòu)圖

[圖片上傳失敗...(image-fa1ffc-1532594075563)]

三、策略模式角色說明

抽象策略(Strategy)角色:定義所有支持的算法的公共接口似芝。通常是以一個接口或抽象來實現(xiàn)那婉。Context使用這個接口來調(diào)用其ConcreteStrategy定義的算法。

具體策略(ConcreteStrategy)角色:以Strategy接口實現(xiàn)某具體算法

環(huán)境(Context)角色:持有一個Strategy類的引用党瓮,用一個ConcreteStrategy對象來配置

四详炬、實例一

比如說購物車系統(tǒng),在給商品計算總價的時候寞奸,普通會員肯定是商品單價乘以數(shù)量呛谜,但是對中級會員提供8者折扣,對高級會員提供7折折扣枪萄,這種場景就可以使用策略模式實現(xiàn):

/**
 * 策略模式實例
 * 
 */
//抽象策略角色《為接口或者抽象類隐岛,給具體策略類繼承》
interface Strategy
{
    public function computePrice($price);
}
 
//具體策略角色-普通會員策略類
class GenernalMember implements Strategy
{
    public function computePrice($price)
    {
        return $price;
    }
}
 
//具體策略角色-中級會員策略類
class MiddleMember implements Strategy
{
    public function computePrice($price)
    {
        return $price * 0.8;
    }
}
 
//具體策略角色-高級會員策略類
class HignMember implements Strategy
{
    public function computePrice($price)
    {
        return $price * 0.7;
    }
}
 
//環(huán)境角色實現(xiàn)類
class Price 
{
    //具體策略對象
    private $strategyInstance;
    
    //構(gòu)造函數(shù)
    public function __construct($instance)
    {
        $this->strategyInstance = $instance;
    }
    
    public function compute($price)
    {
        return $this->strategyInstance->computePrice($price);
    }
}
 
//客戶端使用
$p = new Price(new HignMember());
 
$totalPrice = $p->compute(100);
 
echo $totalPrice; //70

實例二

image

我來解釋下這個思維導(dǎo)圖的過程:

1.Joe做了一套相當(dāng)成功的模擬鴨子的游戲。設(shè)計了一個超類Duck,然后讓各種鴨子繼承這個類瓷翻。

2.后來客戶提出要讓鴨子有飛的能力聚凹。所以Joe就在超類中加了個fly()方法,這樣下面的子類都有飛行的行為齐帚。

問題來了:

  • 原來Duck的子類中竟然有橡皮鴨妒牙,橡皮鴨是不會飛的⊥耍——Joe用重載的方式单旁,把橡皮鴨的fly()方法設(shè)置為空.
  • 覆蓋fly(),我們看到了橡皮鴨的fly()里饥伊,沒有任何代碼象浑,如果以后我們再添加別的不會飛的鴨子蔫饰,那我么還要這么處理嗎?——那么代碼重復(fù)了!

3.上面2的方式我們知道是有問題的,所以Joe想到把Duck做成接口愉豺,這樣每個子類必須實現(xiàn)Duck里的方法篓吁。這樣就保證每個鴨子都能根據(jù)自己的需要添加行為。

問題來了:

  • 產(chǎn)品經(jīng)常處于更新中蚪拦,規(guī)格也在不斷的變化杖剪。導(dǎo)致每當(dāng)有新鴨子的時候,Joe就要被迫檢查一遍子類是否覆蓋了fly()方法驰贷∈⒑伲——當(dāng)你修改某個行為的時候,你必須得往下追蹤并在每一個定義此行為的類中修改它括袒。

4.綜合以上問題次兆,Joe想到了把那些變化的部分從不變化的位置中抽出來。比如锹锰,我們對fly()行為芥炭,做了單獨的接口FlyBehavior。如果鴨子想要飛行功能的時候恃慧,我們就讓鴨子實現(xiàn)FlyBehavior.

5.深造:我們想讓鴨子有不同的飛行功能园蝠,讓它在運行時候做不同的飛行動作。讓鴨子類實現(xiàn)接口痢士,只能讓鴨子有一種行為彪薛。

所以Joe,想到用組合的防止良瞧,當(dāng)鴨子需要其他飛行功能要求的時候陪汽,我們可以用setBehavior()方式,指定性的飛行方式褥蚯。

interface FlyBehavior{
    public function fly();
}
 
class FlyWithWings implements FlyBehavior{
    public function fly(){
        echo "Fly With Wings \n";
    }
}
 
class FlyWithNo implements FlyBehavior{
    public function fly(){
        echo "Fly With No Wings \n";
    }
}
class Duck{
    private $_flyBehavior;
    public function performFly(){
        $this->_flyBehavior->fly();
    }
 
    public function setFlyBehavior(FlyBehavior $behavior){
        $this->_flyBehavior = $behavior;
    }
}
 
class RubberDuck extends Duck{
}
// Test Case
$duck = new RubberDuck();
 
/*  想讓鴨子用翅膀飛行 */
$duck->setFlyBehavior(new FlyWithWings());
$duck->performFly();            
 
/*  想讓鴨子不用翅膀飛行 */
$duck->setFlyBehavior(new FlyWithNo());
$duck->performFly();

五挚冤、策略模式的控制和反轉(zhuǎn)

使用策略模式可以實現(xiàn)Ioc,依賴倒置和控制反轉(zhuǎn)

在原本的類中赞庶,存在一個A類中調(diào)用B類训挡,則A類是依賴于B類的。

通過幾個接口的設(shè)置和策略的解耦歧强,就把依賴進行了反轉(zhuǎn)澜薄,也就是我們在寫A類的時候不需要去實現(xiàn)B類。

只有在最后執(zhí)行的時候才進行綁定摊册。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末肤京,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子茅特,更是在濱河造成了極大的恐慌忘分,老刑警劉巖棋枕,帶你破解...
    沈念sama閱讀 222,183評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異妒峦,居然都是意外死亡重斑,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評論 3 399
  • 文/潘曉璐 我一進店門肯骇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來榆纽,“玉大人待诅,你說我怎么就攤上這事恤煞】鹑椋” “怎么了膨疏?”我有些...
    開封第一講書人閱讀 168,766評論 0 361
  • 文/不壞的土叔 我叫張陵键菱,是天一觀的道長充坑。 經(jīng)常有香客問我熔任,道長拆融,這世上最難降的妖魔是什么蠢琳? 我笑而不...
    開封第一講書人閱讀 59,854評論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮镜豹,結(jié)果婚禮上傲须,老公的妹妹穿的比我還像新娘。我一直安慰自己趟脂,他們只是感情好泰讽,可當(dāng)我...
    茶點故事閱讀 68,871評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著昔期,像睡著了一般已卸。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上硼一,一...
    開封第一講書人閱讀 52,457評論 1 311
  • 那天累澡,我揣著相機與錄音,去河邊找鬼般贼。 笑死愧哟,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的哼蛆。 我是一名探鬼主播蕊梧,決...
    沈念sama閱讀 40,999評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼腮介!你這毒婦竟也來了肥矢?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,914評論 0 277
  • 序言:老撾萬榮一對情侶失蹤叠洗,失蹤者是張志新(化名)和其女友劉穎甘改,沒想到半個月后靴迫,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,465評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡楼誓,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,543評論 3 342
  • 正文 我和宋清朗相戀三年玉锌,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片疟羹。...
    茶點故事閱讀 40,675評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡主守,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出榄融,到底是詐尸還是另有隱情参淫,我是刑警寧澤,帶...
    沈念sama閱讀 36,354評論 5 351
  • 正文 年R本政府宣布愧杯,位于F島的核電站涎才,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏力九。R本人自食惡果不足惜耍铜,卻給世界環(huán)境...
    茶點故事閱讀 42,029評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望跌前。 院中可真熱鬧棕兼,春花似錦、人聲如沸抵乓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽灾炭。三九已至茎芋,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蜈出,已是汗流浹背田弥。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留掏缎,地道東北人皱蹦。 一個月前我還...
    沈念sama閱讀 49,091評論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像眷蜈,于是被迫代替她去往敵國和親沪哺。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,685評論 2 360

推薦閱讀更多精彩內(nèi)容

  • 活著誰也別瞧不起誰, 十年河?xùn)|十年河西, 總有一天我也會出人頭地; 走著誰也別想落下誰籍滴, 你在努力我也沒放棄酪夷, 總...
    菲菲1988閱讀 509評論 0 7
  • “明天我們?nèi)ベ徫锝滞砹耄黄饋韱幔俊蓖砩闲在微信里問我要一個文件勋功,我順手打了這句話坦报,雖然明知道她不會來。 小K狂鞋,我...
    焦糖爆米花閱讀 291評論 3 2
  • 塵歸塵 土歸土 風(fēng)歸雨 云歸月 一切都是最好的開始 一切都是最恰時的安排 一切就是最好的歷練 一切就是最好的成長 ...
    竹青青閱讀 319評論 2 1
  • 想和我一起用高效記憶系統(tǒng)嗎片择?大家快來看看,他們都在自己的“記憶宮殿”里裝了啥骚揍?https://ding.fanqi...
    周助人閱讀 111評論 0 0