PHP 設計模式之策略模式

echo_dump發表於2020-06-16

策略模式 Strategy

  1. 策略模式在分類上屬於行為型

  2. 現在有一個例子,比如有一隻鴨子,有的鴨子是會飛的(野鴨),有的鴨子不會飛(家裡養的鴨子),有的鴨子是會瓜瓜叫的,有的鴨子就不會叫(玩具鴨,
    周黑鴨),有的鴨子會游泳(養的鴨子,野鴨),有的鴨子不會(周黑鴨,玩具鴨,小黃鴨)

  3. 假如利用繼承來實現,那就是先建立一個抽象類,然後野鴨,周黑鴨,家裡養的鴨子,小黃鴨,玩具鴨,都要去繼承我們的抽象類鴨子,

<?php


namespace Strategy;


abstract class DuckTest
{
    /**
     * Notes:介紹鴨子
     * Name: display
     * User: LiYi
     * Date: 2020/6/15
     * Time: 23:44
     * @param string $name
     * @return mixed
     */
    public function display(string $name)
    {
        echo "我是: " . $name;
    }

    public function call()
    {
        echo '鴨子都會叫' . PHP_EOL;
    }

    public function fly()
    {
        echo '鴨子都會飛' . PHP_EOL;
    }

    public function swim()
    {
        echo '鴨子都會游泳' . PHP_EOL;
    }
}
  1. 抽象類裡有很多方法,可能對不同的鴨子,很多都不適用,那麼就需要去重寫它,每一個種類的鴨子都要去重寫這個抽象類的方法,這樣做,很不實用。那麼
    有沒有一個辦法不去重寫這個抽象類呢,其實是有的。比如,還建立一個抽象類的鴨子,鴨子會不會飛,會不會叫,會不會游泳,這三個屬性都把它作為一個介面
<?php


namespace Strategy;


abstract class Duck
{
    protected $fly = null;

    protected $call = null;

    protected $swim = null;
    /**
     * Notes:介紹鴨子
     * Name: display
     * User: LiYi
     * Date: 2020/6/15
     * Time: 23:44
     * @param string $name
     * @return mixed
     */
    public function display(string $name)
    {
        echo "我是: " . $name . PHP_EOL;
    }

    public function call()
    {
        if (!is_null($this->call)) {
            $this->call->call();
        }

    }

    public function fly()
    {
        if (!is_null($this->fly)) {
            $this->fly->fly();
        }
    }

    public function swim()
    {
        if (!is_null($this->swim)) {
            $this->swim->swim();
        }
    }
}
  1. 定義三個介面來描述鴨子的各種能力
namespace Strategy;


interface CallInterface
{
    public function call();
}

interface FlyInterface
{
    public function fly();
}

interface SwimInterface
{
    public function swim();
}
  1. 每種鴨子的能力都不相同,會飛的,不會飛的,飛的不怎樣的,會叫的,不會叫的,叫不出來的,等等,每種能力都有各自的實現。
class NoFly implements FlyInterface
{

    public function fly()
    {
        // TODO: Implement fly() method.
        echo "我是不會飛的鴨子" . PHP_EOL;
    }
}

class GoodFly implements FlyInterface
{

    public function fly()
    {
        // TODO: Implement fly() method.
        echo '我是一個飛的還可以的鴨子' . PHP_EOL;
    }
}

class BadFly implements FlyInterface
{

    public function fly()
    {
        // TODO: Implement fly() method.
        echo '我是一個飛的不怎麼樣的鴨子' . PHP_EOL;
    }
}

class GuaGuaCall implements CallInterface
{

    public function call()
    {
        // TODO: Implement call() method.
        echo '我是一個呱呱叫的鴨子';
    }
}

class LowVoiceCall implements CallInterface
{

    public function call()
    {
        // TODO: Implement call() method.
        echo '我只會小聲叫的鴨子' . PHP_EOL;
    }
}

class NoCall implements CallInterface
{

    public function call()
    {
        // TODO: Implement call() method.
        echo '我是一個不會叫的鴨子' . PHP_EOL;
    }
}
  1. 假如現在有一個野鴨,和一個小黃鴨,那麼我們就可以根據鴨子的各自屬性,來組合鴨子的各自能力,就不需要去重寫抽象類的方法了
class WildDuck extends Duck
{
    public function __construct()
    {
        $this->fly = new GoodFly();
        $this->call = new LowVoiceCall();
    }
}

class YellowDuck extends Duck
{
    public function __construct()
    {
        $this->fly = new BadFly();
        $this->call = new NoCall();
    }
}
  1. 最後測試
class Client
{
    public function __construct()
    {
        $wildDuck = new WildDuck();

        $wildDuck->display('野鴨');
        $wildDuck->fly();
        $wildDuck->swim();
        $wildDuck->call();

        $yellowDuck = new YellowDuck();

        $yellowDuck->display('小黃鴨');
        $yellowDuck->fly();
        $yellowDuck->swim();
        $yellowDuck->call();
    }
}

require '../vendor/autoload.php';
new Client();
/**
* 我是: 野鴨
  我是一個飛的還可以的鴨子
  我只會小聲叫的鴨子
  我是: 小黃鴨
  我是一個飛的不怎麼樣的鴨子
  我是一個不會叫的鴨子
 */
本作品採用《CC 協議》,轉載必須註明作者和本文連結
LIYi ---- github地址

相關文章