設計模式(一)工廠模式Factory(創建型)

  在面向對象編程中, 最通常的方法是一個new操作符產生一個對象實例,new操作符就是用來構造對象實例的。但是在一些情況下, new操作符直接生成對象會帶來一些問題。舉例來說, 許多類型對象的創造需要一系列的步驟: 你可能需要計算或取得對象的初始設置; 選擇生成哪個子對象實例; 或在生成你需要的對象之前必須先生成一些輔助功能的對象。 在這些情況,新對象的建立就是一個 “過程”,不僅是一個操作,像一部大機器中的一個齒輪傳動。

模式的問題:你如何能輕松方便地構造對象實例,而不必關心構造對象實例的細節和復雜過程呢?

解決方案建立一個工廠來創建對象

實現:

一、引言
    1)還沒有工廠時代:假如還沒有工業革命,如果一個客戶要一款寶馬車,一般的做法是客戶去創建一款寶馬車,然后拿來用。
    2)簡單工廠模式:后來出現工業革命。用戶不用去創建寶馬車。因為客戶有一個工廠來幫他創建寶馬.想要什么車,這個工廠就可以建。比如想要320i系列車。工廠就創建這個系列的車。即工廠可以創建產品。
    3)工廠方法模式時代:為了滿足客戶,寶馬車系列越來越多,如320i,523i,30li等系列一個工廠無法創建所有的寶馬系列。于是由單獨分出來多個具體的工廠。每個具體工廠創建一種系列。即具體工廠類只能創建一個具體產品。但是寶馬工廠還是個抽象。你需要指定某個具體的工廠才能生產車出來。
    4)抽象工廠模式時代:隨著客戶的要求越來越高,寶馬車必須配置空調。而且這空調必須對應給系列車才能使用。于是這個工廠開始生產寶馬車和需要的空調。
         最終是客戶只要對寶馬的銷售員說:我要523i空調車,銷售員就直接給他523i空調車了。而不用自己去創建523i空調車寶馬車.
   (我只是舉個例子,說到寶馬配置空調完全是為了舉例,甚至有點扯,哪有車和空調必須對應才能使用?。?br />     這就是工廠模式。
二、分類 
        工廠模式主要是為創建對象提供過渡接口,以便將創建對象的具體過程屏蔽隔離起來,達到提高靈活性的目的。 
工廠模式可以分為三類: 
1)簡單工廠模式(Simple Factory) 
2)工廠方法模式(Factory Method) 
3)抽象工廠模式(Abstract Factory) 
         這三種模式從上到下逐步抽象,并且更具一般性。 
        GOF在《設計模式》一書中將工廠模式分為兩類:工廠方法模式(Factory Method)與抽象工廠模式(Abstract Factory)。將簡單工廠模式(Simple Factory)看為工廠方法模式的一種特例,兩者歸為一類。 
三、區別 
工廠方法模式:
一個抽象產品類,可以派生出多個具體產品類。   
一個抽象工廠類,可以派生出多個具體工廠類。   
每個具體工廠類只能創建一個具體產品類的實例。
抽象工廠模式:
多個抽象產品類,每個抽象產品類可以派生出多個具體產品類。   
一個抽象工廠類,可以派生出多個具體工廠類。   
每個具體工廠類可以創建多個具體產品類的實例。   
區別:
工廠方法模式只有一個抽象產品類,而抽象工廠模式有多個。   
工廠方法模式的具體工廠類只能創建一個具體產品類的實例,而抽象工廠模式可以創建多個。
兩者皆可。 

四、簡單工廠模式 
建立一個工廠(一個函數或一個類方法)來制造新的對象。
分布說明引子:從無到有。客戶自己創建寶馬車,然后拿來用。
 1.jpg

<?php  
/** 
 * 車子系列 
 * 
 */  
Class BWM320{  
function __construct($pa) {  
  
}  
}  
Class BMW523{  
   function __construc($pb){  
  
}  
}  
  
/** 
 *  
 * 客戶自己創建寶馬車 
 */  
class Customer {  
  
   function createBMW320(){  
       return new BWM320();  
   }  
  
   function createBMW523(){  
       return new BMW523();  
   }  
}

       客戶需要知道怎么去創建一款車,客戶和車就緊密耦合在一起了.為了降低耦合,就出現了工廠類,把創建寶馬的操作細節都放到了工廠里面去,客戶直接使用工廠的創建工廠方法,傳入想要的寶馬車型號就行了,而不必去知道創建的細節.這就是工業革命了:簡單工廠模式

即我們建立一個工廠類方法來制造新的對象。如圖:

2.jpg

產品類:

<?php  
/** 
 * 車子系列 
 * 
 */  
abstract Class BWM{  
    function __construct($pa) {  
  
    }  
}  
Class BWM320 extends BWM{  
    function __construct($pa) {  
  
    }  
}  
Class BMW523 extends BWM{  
   function __construc($pb){  
  
   }  
}

 工廠類:

/** 
 *  
 * 工廠創建車 
 */  
class Factory {  
  
  
    static function  createBMW($type){  
        switch ($type) {  
          case 320:  
             return new BWM320();  
          case 523:  
             return new BMW523();  
        //....  
   }  
}

客戶類:

/** 
 *  
 * 客戶通過工廠獲取車 
 */  
class Customer {  
    private $BMW;  
    function getBMW($type){  
        $this?-> BMW =  Factory::createBMW($type);  
    }  
}

      簡單工廠模式又稱靜態工廠方法模式。重命名上就可以看出這個模式一定很簡單。它存在的目的很簡單:定義一個用于創建對象的接口。 
      先來看看它的組成: 
         1) 工廠類角色:這是本模式的核心,含有一定的商業邏輯和判斷邏輯。
         2) 抽象產品角色:它一般是具體產品繼承的父類或者實現的接口。         
         3) 具體產品角色:工廠類所創建的對象就是此角色的實例。在java中由一個具體類實現。 
        下面我們從開閉原則(對擴展開放;對修改封閉)上來分析下簡單工廠模式。當客戶不再滿足現有的車型號的時候,想要一種速度快的新型車,只要這種車符合抽象產品制定的合同,那么只要通知工廠類知道就可以被客戶使用了。所以對產品部分來說,它是符合開閉原則的;但是工廠部分好像不太理想,因為每增加一種新型車,都要在工廠類中增加相應的創建業務邏輯(createBMW($type)方法需要新增case),這顯然是違背開閉原則的??上攵獙τ谛庐a品的加入,工廠類是很被動的。對于這樣的工廠類,我們稱它為全能類 或者上帝類。 
        我們舉的例子是最簡單的情況,而在實際應用中,很可能產品是一個多層次的樹狀結構。由于簡單工廠模式中只有一個工廠類來對應這些產品,所以這可能會把我們的上帝累壞了,也累壞了我們這些程序員:( 
        于是工廠方法模式作為救世主出現了。 工廠類定義成了接口,而每新增的車種類型,就增加該車種類型對應工廠類的實現,這樣工廠的設計就可以擴展了,而不必去修改原來的代碼。
五、工廠方法模式 
        工廠方法模式去掉了簡單工廠模式中工廠方法的靜態屬性,使得它可以被子類繼承。這樣在簡單工廠模式里集中在工廠方法上的壓力可以由工廠方法模式里不同的工廠子類來分擔。 
工廠方法模式組成: 
       1)抽象工廠角色: 這是工廠方法模式的核心,它與應用程序無關。是具體工廠角色必須實現的接口或者必須繼承的父類。在java中它由抽象類或者接口來實現。 
       2)具體工廠角色:它含有和具體業務邏輯有關的代碼。由應用程序調用以創建對應的具體產品的對象。 
       3)抽象產品角色:它是具體產品繼承的父類或者是實現的接口。在java中一般有抽象類或者接口來實現。 
       4)具體產品角色:具體工廠角色所創建的對象就是此角色的實例。在java中由具體的類來實現。 
       工廠方法模式使用繼承自抽象工廠角色的多個子類來代替簡單工廠模式中的“上帝類”。正如上面所說,這樣便分擔了對象承受的壓力;而且這樣使得結構變得靈活 起來——當有新的產品產生時,只要按照抽象產品角色、抽象工廠角色提供的合同來生成,那么就可以被客戶使用,而不必去修改任何已有 的代碼??梢钥闯龉S角色的結構也是符合開閉原則的! 
 3.jpg

代碼如下: 

產品類:

<?php  
/** 
 * 車子系列 
 * 
 */  
abstract Class BWM{  
function __construct($pa) {  
  
}  
}  
Class BWM320 extends BWM{  
function __construct($pa) {  
  
}  
}  
Class BMW523 extends BWM{  
   function __construc($pb){  
  
}  
}
/** 
 * 創建工廠的接口 
 * 
 */  
interface FactoryBMW {   
       function createBMW();   
}   
  
  
/** 
 *  
 * 創建BWM320車 
 */  
class FactoryBWM320 implements FactoryBMW {  
   function  createBMW($type){  
      return new BWM320();  
   }  
  
}  
  
  
/** 
 *  
 * 創建BWM523車 
 */  
class FactoryBWM523 implements FactoryBMW {  
   function  createBMW($type){  
      return new BMW523();  
   }  
}

客戶類:

/** 
 *  
 * 客戶得到車 
 */  
class Customer {  
   private $BMW;  
   function  getBMW($type){  
      switch ($type) {  
        case 320:  
           $BWM320 = new FactoryBWM320();  
           return $BWM320->createBMW();  
        case 523:  
           $BWM523 = new FactoryBWM523();  
           return $BWM320->createBMW();  
            //....  
      }  
  
  }  
}

工廠方法小結: 
        工廠方法模式仿佛已經很完美的對對象的創建進行了包裝,使得客戶程序中僅僅處理抽象產品角色提供的接口。那我們是否一定要在代碼中遍布工廠呢?大可不必。也許在下面情況下你可以考慮使用工廠方法模式: 
     1)當客戶程序不需要知道要使用對象的創建過程。 
     2)客戶程序使用的對象存在變動的可能,或者根本就不知道使用哪一個具體的對象。

       簡單工廠模式與工廠方法模式真正的避免了代碼的改動了?沒有。在簡單工廠模式中,新產品的加入要修改工廠角色中的判斷語句;而在工廠方法模式中,要么將判 斷邏輯留在抽象工廠角色中,要么在客戶程序中將具體工廠角色寫死(就象上面的例子一樣)。而且產品對象創建條件的改變必然會引起工廠角色的修改。
       面對這種情況,我們可以使用反射機制:

class Customer {  
     private $BMW;  
     function  getBMW($type){  
         $class = new ReflectionClass('FactoryBWM' .$type );//建立 'FactoryBWM'這個類的反射類    
          $instance  = $class->newInstanceArgs();//相當于實例化'FactoryBWM' .$type類    
          return $instance->createBMW();  
        //或者直接   
         /** 
         * $instance = new 'FactoryBWM' .$type(); 
         * return $instance->createBMW(); 
         */  
    }  
}

六、抽象工廠模式 
       隨著客戶的要求越來越高,寶馬車需要配置空調。于是這個工廠開始生產寶馬車和配置需要的空調。這時候工廠有二個系列的產品:寶馬車和空調.寶馬車必須使用對應的空調才能使用.這時候分別使用一個車工廠和一個空調工廠都不能滿足我們的需求,我們必須確認車跟空調的對應關系。因此把車工廠跟空調工廠聯系在一起。因此出現了抽象工廠模式。
     可以說,抽象工廠模式和工廠方法模式的區別就在于需要創建對象的復雜程度上。而且抽象工廠模式是三個里面最為抽象、最具一般性的。 
抽象工廠模式的用意為:給客戶端提供一個接口,可以創建多個產品族中的產品對象 ,而且使用抽象工廠模式還要滿足一下條件:
     1)系統中有多個產品族,而系統一次只可能消費其中一族產品。 
     2)同屬于同一個產品族的產品以其使用。 
抽象工廠模式的各個角色(和工廠方法一樣): 
     1)抽象工廠角色: 這是工廠方法模式的核心,它與應用程序無關。是具體工廠角色必須實現的接口或者必須繼承的父類。在java中它由抽象類或者接口來實現。 
     2)具體工廠角色:它含有和具體業務邏輯有關的代碼。由應用程序調用以創建對應的具體產品的對象。
     3)抽象產品角色:它是具體產品繼承的父類或者是實現的接口。
     4)具體產品角色:具體工廠角色所創建的對象就是此角色的實例。

 

其結構:

 4.jpg

我們的例子:
 5.jpg
代碼:

產品類:

<?php  
/** 
 * 車子系列以及型號 
 * 
 */  
abstract class  BWM{  
}  
  
class BWM523 extends  BWM {  
}  
class BWM320 extends  BWM {  
  
  
}  
/** 
 * 空調 
 * 
 */  
abstract class aircondition{  
}  
class airconditionBWM320  extends aircondition {  
  
}  
class airconditionBWM52 extends aircondition {  
  
}

創建工廠類:

/** 
 * 創建工廠的接口 
 * 
 */  
interface FactoryBMW {   
     function createBMW();   
     function createAirC();   
}   
  
  
/** 
 *  
 * 創建BWM320車 
 */  
class FactoryBWM320 implements FactoryBMW {  
    function  createBMW(){  
    return new BWM320();  
}  
function  createAirC(){ //空調  
    return new airconditionBWM320();  
}  
}  
  
  
/** 
 *  
 * 創建BWM523車 
 */  
class FactoryBWM523 implements FactoryBMW {  
    function  createBMW(){  
    return new BWM523();  
}  
function  createAirC(){  
    return new airconditionBWM523();  
}  
}

客戶:

/** 
 *  
 * 客戶得到車 
 */  
class Customer {  
   private $BMW;  
   private $airC;  
   function  getBMW($type){  
       $class = new ReflectionClass('FactoryBWM' .$type );//建立 Person這個類的反射類    
        $instance  = $class->newInstanceArgs();//相當于實例化Person 類    
        $this->BMW =  $instance->createBMW();  
       $this->airC =  $instance->createAirC();  
   }  
}

轉自:http://blog.csdn.net/hguisu/article/details/7505909

原創文章,作者:s19930811,如若轉載,請注明出處:http://www.www58058.com/2951

(0)
s19930811s19930811
上一篇 2015-06-23 09:51
下一篇 2015-06-23 09:57

相關推薦

  • Hadoop新增datanode與SecondaryNameNode

    無論是新增namenode還是SecondaryNameNode,操作方法大致相同 一、如果新增datanode,需要保證namenode能無密碼ssh連接到新datanode 如果是添加SecondaryNameNode,則需保證其能無密碼ssh連接至各datanode和namenode,namenode也需要能無密碼連接到新SecondaryNameNo…

    Linux干貨 2015-03-08
  • 在VMware Workstation上安裝CentOS 7

    1.新建虛擬機設備設置 2.開啟此虛擬機,進行安裝設置    需設置4處  時間,SOFTWARE SELECTION,分區,NETWORK & HOST NAME    (1) 首先 時間設置,選中上海時間,設置現在的Windows時間,設置好后,點擊Done退出。(下面同意Done保存退…

    2017-07-15
  • grep簡述

    grep(Globel Search Regular Expression and Printing out the line) 它能使用正則表達式搜索文本,并把匹配的行打印出來。 grep包括grep、egrep和fgrep。 egrep表示擴展的grep,相比grep支持更多的匹配模式, “grep -E”相當于egrep。 fgrep是fast gre…

    2017-04-06
  • bash的工作特性-命令執行狀態返回值、命令行展開

    bash的基礎特性:命令的執行狀態結果 命令執行的狀態結果:      bash通過狀態返回值來輸出此結果:           成功:0           失?。?-255 命令執行完成之后,其狀態返回值會保存于bash的特殊…

    Linux干貨 2016-08-22
  • 使用NFS服務和samba部署wordpress

             centos 7.3主機一臺   centos 6.8主機一臺  使用yum安裝的mysql(7以后使用yum裝mysql叫mariadb)         我事先查看了一…

    2017-05-02
  • 計算機的組成及其功能

    計算機的組成及其功能 計算機由五部分組成 運算器 實現算術運算和邏輯運算(和控制器組成CPU) 控制器 控制總線的使用權限,完成尋址和控制對內存當中的訪問權限是做讀訪問還是寫訪問 存儲器 內存,RAM(Random Access Memory) 輸入(Input) 下指令,提供數據 輸出(Output) 輸出數據加工的結果

    2018-02-22
欧美性久久久久