PHP設計模式之工廠方法模式

PHP設計模式之工廠方法模式

上回說到,簡單工廠不屬於GoF的二十三種設計模式,這回可就來真傢伙了,大名頂頂的工廠方法模式前來報道!php

GoF類圖解釋

工廠方法模式對比簡單工廠來講,最核心的一點,其實就是將實現推遲到子類。怎麼理解呢?咱們能夠將上回的簡單工廠當作父類,而後有一堆子類去繼承它。createProduct()這個方法在父類中也變成一個抽象方法。而後全部的子類去實現這個方法,再也不須要用switch去判斷,子類直接返回一個實例化的對象便可。git

GoF定義:定義一個用於建立對象的接口,讓子類決定實例化哪個類。Factory Method使一個類的實例化推遲到其子類。github

GoF類圖設計模式

工廠方法結構類圖

  • 類圖中的Product爲產品
  • 類圖中的Creator爲建立者
  • 建立者父類有一個抽象的FactoryMethod()工廠方法
  • 全部建立者子類須要實現這個工廠方法,返回對應的具體產品
  • 建立者父類能夠有一個AnOperation()操做方法,直接返回product,能夠使用FactoryMethod()去返回,這樣外部只須要統一調用AnOperation()

代碼實現this

首先是商品相關的接口和實現類,和簡單工廠的相似:阿里雲

// 商品接口
interface Product{
    function show() : void;
}

// 商品實現類A
class ConcreteProductA implements Product{
    public function show() : void{
        echo "I'm A.\n";
    }
}
複製代碼

接下來是建立者的抽象和實現類:spa

// 建立者抽象類
abstract class Creator{

    // 抽象工廠方法
    abstract protected function FactoryMethod() : Product;

    // 操做方法
    public function AnOperation() : Product{
        return $this->FactoryMethod();
    }
}

// 建立者實現類A
class ConcreteCreatorA extends Creator{
    // 實現操做方法
    protected function FactoryMethod() : Product{
        return new ConcreteProductA();
    }
}
複製代碼

這裏和簡單工廠就有了本質的區別,咱們去掉了噁心的switch,讓每一個具體的實現類來進行商品對象的建立。沒錯,單一和封閉,每一個單獨的建立者子類只在工廠方法中和一個商品有耦合,有沒有其餘商品和其餘的工廠來跟客戶合做過這個子類徹底不知道。設計

一樣仍是拿手機來比喻:我是一個賣手機的批發商(客戶Client,業務方),我須要一批手機(產品ProductA),因而我去讓富X康(工廠Creator)來幫我生產。我跟富士康說明了需求,富士康說好的,讓個人衡陽工廠(ConcreteCreatorA)來搞定,不須要總廠上,你這小單子,灑灑水啦。而後過了一陣我又須要另外一種型號的手機(產品ProductB),富士康看了看後又讓鄭州富士康(ConcreteCreatorB)來幫我生產。反正無論怎麼樣,他們老是給了我對應的手機。並且鄭州工廠並不知道衡陽工廠生產過什麼或者有沒有跟我合做過,這一切只有我和總工廠知道。code

完整代碼:工廠方法模式cdn

實例

場景:光說不練假把式,把上回的短信發送改造改造,咱們依然仍是使用上回的那幾個短信發送商。畢竟你們已經很熟悉了嘛,不過之後要更換也說不定,商場如戰場,你們仍是利益爲先。這樣的話,咱們經過工廠方法模式來進行解耦,就能夠方便的添加修改短信提供商咯。

短信發送類圖

短信發送工廠方法

代碼實現

<?php

interface Message {
    public function send(string $msg);
}

class AliYunMessage implements Message{
    public function send(string $msg){
        // 調用接口,發送短信
        // xxxxx
        return '阿里雲短信(原阿里大魚)發送成功!短信內容:' . $msg;
    }
}

class BaiduYunMessage implements Message{
    public function send(string $msg){
        // 調用接口,發送短信
        // xxxxx
        return '百度SMS短信發送成功!短信內容:' . $msg;
    }
}

class JiguangMessage implements Message{
    public function send(string $msg){
        // 調用接口,發送短信
        // xxxxx
        return '極光短信發送成功!短信內容:' . $msg;
    }
}


abstract class MessageFactory{
    abstract protected function factoryMethod();
    public function getMessage(){
        return $this->factoryMethod();
    }
}

class AliYunFactory extends MessageFactory{
    protected function factoryMethod(){
        return new AliYunMessage();
    }
}

class BaiduYunFactory extends MessageFactory{
    protected function factoryMethod(){
        return new BaiduYunMessage();
    }
}

class JiguangFactory extends MessageFactory{
    protected function factoryMethod(){
        return new JiguangMessage();
    }
}

// 當前業務須要使用百度雲
$factory = new BaiduYunFactory();
$message = $factory->getMessage();
echo $message->send('您有新的短消息,請查收');
複製代碼

完整源碼:短信發送工廠方法

說明

  • 和類圖徹底一致,基本不須要什麼說明了吧,注意工廠方法模式的特色,實現推遲到了子類!!
  • 業務調用的時候須要耦合一個Factory子類。確實是這樣,若是你想一個統一的出口來調用,請在外面加一層簡單工廠就好啦,這就當成一道思考題吧
  • 不拘泥於目前的形式,能夠不用抽象類,直接用一個接口來定義工廠方法,摒棄掉getMessage()方法,外部直接調用公開的模板方法(factoryMethod)便可

下期看點

抽象工廠模式,老大哥即將登場。壓軸的老是最強悍的,讓咱們看看老大哥的本事!

相關文章
相關標籤/搜索