設計模式[創建型]02--工廠方法模式(Factory)

一、簡介

工廠方法模式(Factory Method Pattern)又稱爲 工廠模式,也叫虛擬構造器(Virtual Constructor)模式或者多態工廠(Polymorphic Factory)模式,它屬於類創建型模式。在工廠方法模式中,工廠父類負責定義創建產品對象的公共接口,而工廠子類則負責生成具體的產品對象,這樣做的目的是將產品類的實例化操作延遲到工廠子類中完成,即通過工廠子類來確定究竟應該實例化哪一個具體產品類。爲系統結構提供靈活的動態擴展機制,減少了耦合。

根據抽象程度的不同,工廠模式可化分爲三種:

  • 簡單工廠模式
  • 工廠方法模式
  • 抽象工廠模式

二、原理

在簡單工廠模式中只提供一個工廠類,該工廠類處於對產品類進行實例化的中心位置,它需要知道每一個產品對象的創建細節,並決定何時實例化哪一個產品類。簡單工廠模式最大的缺點是當有新產品要加入到系統中時,必須修改工廠類,需要在其中加入必要的業務邏輯,這違背了“開閉原則”。此外,在簡單工廠模式中,所有的產品都由同一個工廠創建,工廠類職責較重,業務邏輯較爲複雜,具體產品與工廠類之間的耦合度高,嚴重影響了系統的靈活性和擴展性,而工廠方法模式則可以很好地解決這一問題。

在工廠方法模式中,我們不再提供一個統一的工廠類來創建所有的產品對象,而是針對不同的產品提供不同的工廠,系統提供一個與產品等級結構對應的工廠等級結構。工廠方法模式定義如下:

工廠方法模式(Factory Method Pattern):定義一個用於創建對象的接口,讓子類決定將哪一個類實例化。工廠方法模式讓一個類的實例化延遲到其子類。工廠方法模式又簡稱爲工廠模式(Factory Pattern),又可稱作虛擬構造器模式(Virtual Constructor Pattern)或多態工廠模式(Polymorphic Factory Pattern)。工廠方法模式是一種類創建型模式。

工廠方法模式提供一個抽象工廠接口來聲明抽象工廠方法,而由其子類來具體實現工廠方法,創建具體的產品對象。工廠方法模式結構如圖2所示:

三、類結構

工廠方法模式定義一個用於創建對象的接口,讓子類決定哪個類實例化。 他可以解決簡單工廠模式中的封閉開放原則問題。

與簡單工廠模式相比,工廠方法模式最重要的區別是引入了抽象工廠角色,抽象工廠可以是接口,也可以是抽象類或者具體類。

結構如下:

角色 類別 簡述
Product 產品類 一般是一個抽象類或是接口
ConcreteProduct 具體的產品類 實現或是繼承 Product
Factory 工廠類 抽象工廠
ConcreteFactory 具體的工廠類 實現或是繼承Factory
  • Product(抽象產品):它是定義產品的接口,是工廠方法模式所創建對象的超類型,也就是產品對象的公共父類。
  • ConcreteProduct(具體產品):它實現了抽象產品接口,某種類型的具體產品由專門的具體工廠創建,具體工廠和具體產品之間一一對應。
  • Factory(抽象工廠):在抽象工廠類中,聲明瞭工廠方法(Factory Method),用於返回一個產品。抽象工廠是工廠方法模式的核心,所有創建對象的工廠類都必須實現該接口。
  • ConcreteFactory(具體工廠):它是抽象工廠類的子類,實現了抽象工廠中定義的工廠方法,並可由客戶端調用,返回一個具體產品類的實例。

四、UML圖

五、代碼分析

比如,我們需要設計一個日誌記錄器:

1、抽象產品類

//日誌記錄器接口:抽象產品  
interface Logger {  
    public function writeLog();  
}  

2、具體產品類

//1)數據庫日誌記錄器:具體產品  
class DatabaseLogger implements Logger {  
    public function writeLog() {  
        echo "數據庫日誌記錄。"; 
    }  
}  

//2)文件日誌記錄器:具體產品  
class FileLogger implements Logger {  
    public function writeLog() {  
        echo "文件日誌記錄。";  
    }  
}  

3、抽象工廠類

//日誌記錄器工廠接口:抽象工廠  
interface LoggerFactory {  
    public function createLogger();  
}  

4、具體工廠類
在實際使用時,具體工廠類在實現工廠方法時除了創建具體產品對象之外,還可以負責產品對象的初始化工作以及一些資源和環境配置工作,例如連接數據庫、創建文件等。

//1)數據庫日誌記錄器工廠類:具體工廠  
class DatabaseLoggerFactory implements LoggerFactory {  
    public function createLogger() {  
            //連接數據庫,代碼省略  
            //創建數據庫日誌記錄器對象  
            $logger = new DatabaseLogger();   
            //初始化數據庫日誌記錄器,代碼省略  
            return $logger; 
    }     
}  

//2)文件日誌記錄器工廠類:具體工廠  
class FileLoggerFactory implements LoggerFactory {  
    public function createLogger() {  
            //創建文件日誌記錄器對象  
            $logger = new FileLogger();   
            //創建文件,代碼省略  
            return $logger;  
    }     
}

5、例子

$file_factory = new FileLoggerFactory(); //可引入配置文件實現  
$file_logger = factory->createLogger();  
$file_logger->writeLog(); 

$db_lfactory = new DatabaseLoggerFactory(); //可引入配置文件實現
$db_logger = factory->createLogger();  
$db_logger->writeLog(); 

輸出結果如下:

文件日誌記錄。
數據庫日誌記錄。

六、特點

工廠方法模式是簡單工廠模式的延伸,它繼承了簡單工廠模式的優點,同時還彌補了簡單工廠模式的不足。工廠方法模式是使用頻率最高的設計模式之一,是很多開源框架和API類庫的核心模式。

1、 優點

  • 在工廠方法模式中,工廠方法用來創建客戶所需要的產品,同時還向客戶隱藏了哪種具體產品類將被實例化這一細節,用戶只需要關心所需產品對應的工廠,無須關心創建細節,甚至無須知道具體產品類的類名。
  • 基於工廠角色和產品角色的多態性設計是工廠方法模式的關鍵。它能夠讓工廠可以自主確定創建各種產品對象,而如何創建這個對象的細節則完全封裝在具體工廠內部。工廠方法模式之所以又被稱爲多態工廠模式,就正是因爲所有的具體工廠類都具有同一抽象父類。
  • 使用工廠方法模式的另一個優點是在系統中加入新產品時,無須修改抽象工廠和抽象產品提供的接口,無須修改客戶端,也無須修改其他的具體工廠和具體產品,而只要添加一個具體工廠和具體產品就可以了,這樣,系統的可擴展性也就變得非常好,完全符合“開閉原則”。

2、 缺點

  • 在添加新產品時,需要編寫新的具體產品類,而且還要提供與之對應的具體工廠類,系統中類的個數將成對增加,在一定程度上增加了系統的複雜度,有更多的類需要編譯和運行,會給系統帶來一些額外的開銷。
  • 由於考慮到系統的可擴展性,需要引入抽象層,在客戶端代碼中均使用抽象層進行定義,增加了系統的抽象性和理解難度,且在實現時可能需要用到DOM、反射等技術,增加了系統的實現難度。

3、 適用場景

滿足以下條件時,可以考慮使用工廠模式方法:

  • 一個類不知道它所需要的對象的類:在工廠方法模式中,客戶端不需要知道具體產品類的類名,只需要知道所對應的工廠即可,具體的產品對象由具體工廠類創建;客戶端需要知道創建具體產品的工廠類。
  • 一個類通過其子類來指定創建哪個對象:在工廠方法模式中,對於抽象工廠類只需要提供一個創建產品的接口,而由其子類來確定具體要創建的對象,利用面向對象的多態性和里氏代換原則,在程序運行時,子類對象將覆蓋父類對象,從而使得系統更容易擴展。
  • 將創建對象的任務委託給多個工廠子類中的某一個,客戶端在使用時可以無須關心是哪一個工廠子類創建產品子類,需要時再動態指定,可將具體工廠類的類名存儲在配置文件或數據庫中。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章