Chap3:建立型設計模式————工廠方法設計模式(上)

建立型設計模式

包括如下五種:php

  • 抽象工廠css

  • 生成器html

  • 工廠方法設計模式

  • 原型編輯器

  • 單例this

咱們選擇工廠方法和原型模式做爲將用PHP實現的建立型設計的例子
工廠方法模式是這5個設計模式中惟一的一種類設計模式
原型模式屬於對象類模式,可使用PHP_clone方法實現。首先基於原型實例化(建立)一個對象,而後由這個實例化對象進一步克隆其餘對象
使用建立型模式時,最有意思的是,當程序和系統愈來愈依賴於對象組合而不是依賴於類繼承時,建立型模式中的程序變成由對象構成的系統,而對象又由其餘對象組合而成,因此任何單個對象的建立都不該該依賴於建立者spa

工廠方法模式

概念:工廠方法模式就是要建立某種東西,對於工廠方法模式,要建立的東西是一個產品,這個產品與建立它的類之間不存在綁定,爲了保持這種鬆耦合,客戶會經過一個工廠發出請求,再由工廠建立所請求的產品。利用工廠方法模式,請求者發出請求,而不具體建立產品。
什麼時候使用:若是實例化對象的子類可能變化,就要使用工廠方法模式
Why:對象的數目和類型都是未知的,一個類沒法預計它要建立的對象數目,因此你不但願類與它要建立的類緊密綁定設計

案例模型:
clipboard.pngcode

步驟:orm

第一步是創建工廠:Creator接口

<?php
//Creator.php
abstract class Creator{
    protected abstract function factoryMethod();
    public function startFactory(){
        $mfg = $this->factoryMethod();
        return $mfg;
    }
}
?>

注意到,僞代碼註釋提示startFactory()方法須要返回一個產品(product),在實現中startFactory()但願factoryMethod()返回一個產品對象,因此,factoryMethod()的具體實現要構建並返回由一個按Product接口實現的產品對象

下面有兩個工廠類擴展了Creator,並實現了factoryMethod()方法,factoryMethod()實現經過一個Product方法(getProperties())返回一個文本或圖像產品,TextFactory和GraphicFactory實現中加入了這些內容

<?php
//TextFactory.php
include_once('Creator.php');
include_once('TextProduct.php');
class TextFactory extends Creator{
    protexted function factoryMethod(){
        $product = new TextProduct();
        return ($product->getProperties());
    }
}
?>
<?php
//TextFactory.php
include_once('Creator.php');
include_once('GraphicProduct.php');
class GraphicFactory extends Creator{
    protexted function factoryMethod(){
        $product = new GraphicProduct();
        return ($product->getProperties());
    }
}
?>

工廠方法設計模式中的第二個接口是Product。因爲這是第一個實現,也是最簡單的實現,全部文本和圖像屬性都只實現一個方法getProperties():創建方法而無屬性,咱們能夠明確想要用這個方法作什麼(好比能夠有個返回值),只要方法名和可見性與簽名一致就不會有問題

<?php
//Product.php
interface Product{
    public function getProperties();
}
?>

能夠利用這個實現,使得同一個方法getProperties()多態,分別返回圖像和文字,以下所示

<?php
//TextProduct.php
include_once('Prouduct.php');
class TextProduct implements Product{
    private $mfgProduct;
    public function getProperties(){
        $this->mfgProduct = "This is a Text<br";
        return $this->mfgProduct;
    }
}
?>
<?php
//Graphic.php
include_once('Product.php');
class GraphicProduct implements Product{
    private $mfgProduct;
      public function getProperties(){
        $this->mfgProduct = "This is a Graphic<br>";
        return $this->mfgProduct;
    }
}
?>

上面你看到的This is a Graphic以及This is text,能夠替換成你想放入的其它東西,工廠設計會建立這個對象,並把它返回給Client來使用。
這兩個工廠和產品分別覆蓋了抽象方法,來建立兩個不一樣的工廠和產品,它們都符合所實現的接口

客戶
這個模式最後一個參與者是隱含的(上面模型圖中顏色較淡的框):客戶。咱們並不但願Client類直接作出產品請求。實際上,咱們但願可以經過Creator接口作出請求,這樣一來,若是之後咱們增長產品或者工廠,客戶能夠作一樣的請求來獲得更多類型的產品,而不會破壞這個應用

<?php
//Client.php
include_once('GraphicFactory.php');
include_once('TextFactory.php');
class Client{
    private $someGraphicObject;
    private $someTextObject;
    public function __construct(){
        $this->someGraphicObject = new GraphicFactory();
        echo $this->someGraphicObject->startFactory();
         $this->someTextObject = new TextFactory();
        echo $this->someTextObject->startFactory();
    }
}
$worker = new Client();
?>

注意Client對象並無向產品直接作出請求,而是經過工廠來請求,重要的是,客戶並不實現產品特性,而留給產品實現來體現。


在本章有個例子,是對上面代碼的改進,也能夠稱做是在工廠中修改產品,可是本猿覺得,例子彷佛舉的不是很好,它把Html代碼嵌套在php代碼中,放在了產品類下的getProperties方法中,以供客戶調用的時候返回,因此我我的以爲這種方法不是很好,一大段代碼放在php中,也不方便編輯器編輯。設計模式是爲了加快開發速度,這樣的方法我拔苗助長。做者是專家,可能也有出於其它考慮。不過裏面有一個觀點我仍是贊成的,其中有一個輔助類的觀點。
所謂輔助類,就是把一些任務給一個單獨的對象來處理,而不是結合到某個參與者中。相似地,若是須要重用一組HTML標記,能夠把它們打包到另外一個對象中以便重用。下面是一個例子

<?php
class FormatHelper{
    private $topper;
    private $bottom;
    public function addTop(){
        $this->topper = "<!doctype html><html><head>
        <link rel='stylesheet' type='text/css' href='products.css'/>       
        <meta charset='UTF-8'>
        <title>Map Factory</title>
        </head> <body>";
        return $this->topper;
    }
    public function closeUp(){
        $this->bottom = "</body></html>";
        return $this->bottom;
    }
}
?>

增長新產品和參數化請求

clipboard.png

上圖與以前的類圖不一樣,它們完成一樣的目標,不過它們的實現有所不一樣。這就是參數化工廠方法設計模式(上圖)與通常的工廠方法設計模式(原類圖)的主要區別之一,即客戶包含工廠和產品的引用。在參數化請求中,Client類必須指定產品,而不僅是產品工廠,factoryMethod()操做中的參數是由客戶傳入的一個產品,因此客戶必須指出它想要的具體產品,不過,這個請求仍然經過Creator接口發出,因此,儘管客戶包含一個產品引用,但經過Creator,客戶仍與產品分離

一個工廠多個產品

對於大多數請求,參數化工廠方法更爲簡單,由於客戶只須要處理一個具體工廠,工廠方法操做有一個參數,指示須要建立的產品。而在原來的設計中,每一個產品都有本身的工廠,不須要另外傳遞參數,產品實現依賴於各個產品的特定工廠。

要從參數化工廠方法設計模式實現多個產品,只需使用Product接口實現多個具體產品,另外,因爲具體產品要同時包含文本和圖像,因此在這個例子中,並非分別有這兩個單獨的產品,能夠創建一個類,將文本和圖像做爲一個贊成的實體來處理,這並不違反單一職責原則,即每一個類應當只有一個職責。對於這個類來講,這個單一職責就是顯示描述一個區域的文本和圖像

新工廠

新工廠與原來的工廠相似,不過它們還包含一個參數和代碼提示。

<?php
//Creator.php
abstract class Creator{
    protected abstract function factoryMethod(Product $product);
    
    public function doFactory($productNow){
        $countryProduct = $productNow;
        $mfg = $this->factoryMethod($countryProduct);
        return $mfg;
    }
}
?>

新的Creator抽象類中能夠看到,factoryMethod()和startFactory操做都須要一個參數。另外代碼提示只是了一個Product對象,而不是Prodcut一個特定實現,因此能夠接受Product的任何具體實例,下面來看看具體的建立者CountryFactory

<?php
//CountryFactory.php
include_once('Creator.php');
inlcude_once('Product.php');
class CountryFactory extends Creator{
    private $country;
    protected function factoryMethod(Product $product){
        $this->country = $product;
        return ($this->country->getProperties());
    }
}
?>

這個具體建立者包含一個私有變量$country,其中包含客戶請求的特定產品,它再使用Product方法getProperties()將產品返回給客戶

與試圖讓任意數目的類和對象都保持不變相比,保持接口不變要容易得多。正是由於這個緣由,使用工廠方法模式能夠簡化複雜的建立過程,關鍵就在於它在維持一個公共接口

本文參考書籍:《Learnig PHP設計模式》第2部分第5章

相關文章
相關標籤/搜索