【面向對象的PHP】之模式:工廠方法

工廠方法模式

面向對象的設計強調「抽象類高於實踐」,儘量的將代碼設計的通常化,而非特殊化——也就是下降耦合,提高標準性。因而,前輩們便設計了「特定類處理實例化」的工廠方法。segmentfault

問題

Appointment類須要解析BloggsCal數據格式,在類內部,咱們將數據格式寫死爲BloggsCal,這將會形成耦合,並且實際上,將來業務需求要面臨更多的數據格式。設計模式

實現

這個時候咱們引入工廠方法模式,設置CommsManager類(創造者,creater)、ApptEncoder類(產品,Product)。架構

接下來,用戶只須要調用CommsManager對象的getApptEncoder方法,就能夠獲得他們須要的對象,而無需關注這個對象究竟是哪一種數據格式。app

abstract class ApptEncoder {
    abstract function encode();
}

class BloggsApptEncoder extends ApptEncoder {
    function encode()
    {
        return "數據格式爲BloggsCal。";
    }
}

class MegaApptEncoder extends ApptEncoder {
    function encode()
    {
        return "數據格式爲MegaCal。";
    }
}

class CommsManager {
    const BLOGGS = 1;
    const MEGA = 2;
    private $mode = 1;

    function __construct( $mode ) {
        $this->mode = $mode;
    }

    function getApptEncoder() {
        switch ( $this->mode ) {
            case ( self::MEGA ) :
                return new MegaApptEncoder();
            default:
                return new BloggsApptEncoder();
        }
    }

    function getHeaderText() {
        switch ( $this->mode ) {
            case ( self::MEGA ):
                return "Mega格式的表頭";
            default:
                return "BloggsCal格式的表頭";
        }
    }

    function getFootText() {
        switch ( $this->mode ) {
            case ( self::MEGA ):
                return "Mega格式的腳頁";
            default:
                return "BloggsCal格式的腳頁";
        }
    }
}

$comms = new CommsManager( CommsManager::MEGA );
$apptEncoder = $comms->getApptEncoder();
echo $apptEncoder->encode();

注意到CommsManager類的三個getXXX方法了嗎?this

一旦數據格式增多、功能增長、數據格式間存在業務差別,就會形成一個新問題:大量的判斷語句——包括我本身在內的一些人認爲,這是代碼腐爛的象徵。設計

至少,當重複的代碼開始蔓延,咱們不該該感到樂觀。(儘管下面的處理方法,在必定程度上也重複了這個錯誤code

面對上述難題,咱們有了下列三條要求:面向對象設計模式

  1. 在代碼運行時,才能瞭解咱們要生成的對象類型(實時傳參,注意那句:$comms = new CommsManager( CommsManager::MEGA ));對象

  2. 相對輕鬆的加入新數據格式(Product);get

  3. 每一個產品類型都能輕鬆加入訂製化功能。

既然如此,咱們乾脆將 數據格式們 從CommsManager中剝離出來,造成單獨的子類。

// 產品抽象類、子類的代碼,同上。

abstract class CommsManager {
    abstract function getApptEncoder();
    abstract function getHeaderText();
    abstract function getFooterText();
}

class BloggsCommsManager extends CommsManager {
    function getApptEncoder() {
        return new BloggsApptEncoder();
    }

    function getHeaderText() {
        return "BloggsCal格式的表頭";
    }

    function getFooterText() {
        return "BloggsCal格式的腳頁";
    }
}

class MegaCommsManager extends CommsManager {
    function getApptEncoder() {
        return new MegaApptEncoder();
    }

    function getHeaderText() {
        return "MegaCal格式的表頭";
    }

    function getFooterText() {
        return "MegaCal格式的腳頁";
    }
}

$comms = new BloggsCommsManager();
$apptEncoder = $comms->getApptEncoder();
echo $apptEncoder->encode();

結果

這樣知足了上述的三個要求,可我想,聰明的你已經注意到了:必定程度上,建立者/產品們 產生了代碼重複。並且,問題被轉移到了工廠方法中,咱們目前只是處理了Appointment功能,若是咱們加入TodoList功能呢?

答案很明顯,咱們須要:能夠同時處理一組相關實現的架構,解決之道就在下一篇文章:抽象工廠模式。

面向對象設計模式 - 目錄

相關文章
相關標籤/搜索