PHP 行為型設計模式(一)

fangle發表於2017-05-22

前言

根據 GOF 一書,行為型設計模式共有十一種。

行為型模式:策略模式模板方法模式觀察者模式迭代子模式責任鏈模式命令模式備忘錄模式狀態模式訪問者模式中介者模式直譯器模式

十一種行為型設計模式可以大致分為四類:

  • 父類與子類關係
  • 兩個類之間
  • 類的狀態
  • 通過中間類

本文主要是介紹第一類行為型設計模式
父類與子類關係:

  • 策略模式 (Strategy Pattern)
  • 模板模式 (Template Pattern)

PHP設計模式(十二)—策略模式 ( Strategy Pattern )

策略模式(Strategy Pattern):定義一系列演算法,將每一個演算法封裝起來,並讓它們可以相互替換。策略模式讓演算法獨立於使用它的客戶而變化,也稱為政策模式(Policy)

(一)為什麼需要策略模式

1,在有多種演算法相似的情況下,使用 if...else 所帶來的複雜和難以維護。

2,利用物件導向的繼承和多型機制,將多個演算法解耦。避免類中出現太多的if-else語句

(二)策略模式 UML圖

PHP 行為型設計模式(一)
Strategy Pattern

Context(應用場景):
1、需要使用ConcreteStrategy提供的演算法。
2、 內部維護一個Strategy的例項。
3、 負責動態設定執行時Strategy具體的實現演算法。
4、負責跟Strategy之間的互動和資料傳遞。
Strategy(抽象策略類)
定義了一個公共介面,各種不同的演算法以不同的方式實現這個介面,Context使用這個介面呼叫不同的演算法,一般使用介面或抽象類實現。
ConcreteStrategy(具體策略類)
實現了Strategy定義的介面,提供具體的演算法實現。

(三)簡單例項

如果我們現在在做一個商城,使用者來了,我們想向其推薦對應的商品。比如說一個女性使用者登入的話,我們就問她需要衣服,男性使用者就推薦螺絲刀,不確定性別就推薦《葵花寶典》

<?php
//抽象策略介面
abstract class Strategy{
  abstract function peddle();
}

//具體封裝的策略方法   女性使用者策略
class ConcreteStrategyA extends Strategy
{
    public function peddle(){
        echo '美女穿這件衣服肯定很好看'.PHP_EOL;
    }
}

//男性使用者策略
class ConcreteStrategyB extends Strategy
{
    public function peddle(){
        echo '每一個男人都需要一個工具箱,充實工具箱,從購買各種螺絲刀開始'.PHP_EOL;
    }

}

//未知性別使用者策略
class ConcreteStrategyC extends Strategy
{
  public function peddle(){
        echo '骨骼清奇,這本《葵花寶典》最適合你'.PHP_EOL;
    }
}

//環境類
class Context{
    protected $strategy;

    public function __construct(Strategy $strategy)
    {
      $this->strategy = $strategy;
    }

    public function request()
    {
      $this->strategy->peddle($this);
    }
}

//若處於女性使用者環境
$female_context = new Context(new ConcreteStrategyA);
$female_context->request();
//若處於男性使用者環境
$male_context = new Context(new ConcreteStrategyB);
$male_context->request();
//若處於未知性別使用者環境
$unknow_context = new Context(new ConcreteStrategyC);
$unknow_context->request();複製程式碼

這裡我們可以看到,我們可以通過不同的環境選擇不同的策略,使用者性別的判斷 如果對於一個商城系統來說,完全可以在使用者登陸的時候通過資料庫的使用者資訊得到,然後做出判斷,選擇適合的策略。

而且策略模式最顯而易見的優勢,就是如果我想增加一個新的策略怎麼辦?比如說,如果使用者是小孩,就給他推薦《五年中考三年模擬》。是的,相信你們心裡已經有答案了。那就是,再增加一個具體策略類。


PHP設計模式(十三)—模板模式(Template Pattern)

模板模式 (Template Pattern): 定義一個操作中的演算法的骨架,而將一些步驟延遲到子類中。模板模式使得子類可以不改變一個演算法的結構即可重定義該演算法的某些特定步驟。

(一)為什麼需要模板模式

1,一次性實現一個演算法的不變的部分,並將可變的行為留給子類來實現。

2, 多個子類有相同的方法,邏輯基本相同時。可將相同的邏輯程式碼提取到父類

3,重構時,將相同程式碼抽取到父類,然後通過鉤子函式約束其行為

(二)模板模式 UML圖

PHP 行為型設計模式(一)
Template Pattern

(三)簡單例項

這裡舉《PHP設計模式》的一個例子:一個銀行可以有許多不同型別的銀行賬戶,但是所有賬戶的處理方式基本相同。假設我們現在有兩類賬戶,一類是普通賬戶,一類是信用卡賬戶。現在進行支付,信用卡允許透支,普通賬戶不允許透支,即賬戶金額不允許小於零

<?php 
//抽象模板類
abstract class Template{
    protected $balance = 100;       //賬戶餘額,為測試方便,直接賦初值100
    //結算方法
    abstract protected function adjust($num);
    //支付資訊顯示 
    abstract protected function display($num);
    final public function apply($num){
        $this->adjust($num);
        $this->display($num);
    }
}

//普通賬戶
class Account extends Template{
    protected $falg;  //用於判斷支付是否成功
    protected function adjust($num){
        if($this->balance > $num){//只有餘額大於所需支付金額才允許支付
            $this->balance-=$num;
            $this->falg = true;
        }else{
            $this->falg = false;
        }
    }
    protected function display($num){
        if($this->falg){
            echo '支付成功,所剩餘額為'.$this->balance.PHP_EOL;
        }else{
            echo '餘額不足,支付失敗,所剩餘額為'.$this->balance.PHP_EOL;
        }
    }
}

//信用卡使用者
class Credit extends Template{
    protected function adjust($num){
        $this->balance-=$num;
    }
    protected function display($num){
        echo '感謝您使用信用支付,所剩餘額為'.$this->balance.PHP_EOL;
    }
}

//普通賬戶使用
$account = new Account;
//普通賬戶使用
$account -> apply(80);
//普通賬戶透支
$account -> apply(30);

//信用卡賬戶使用
$credit = new Credit;
$credit -> apply(200);複製程式碼

模板模式的好處在於行為由父類控制,而具體的實現由子類實現。這就可以把一個操作延遲繫結到子類上。還有另一種應用是把複雜的核心程式碼設計為模板方法,周邊的相關細節則由子類實現。


上一篇PHP結構型設計模式(下)

感謝閱讀,由於筆者也是初學設計模式,能力有限,文章不可避免地有失偏頗
後續更新 PHP行為型設計模式(二)介紹,歡迎大家評論指正


我最近的學習總結:


PHP 行為型設計模式(一)
歡迎大家關注我的微信公眾號 火風鼎

相關文章