設計模式學習筆記(五):工廠方法模式
阿新 • • 發佈:2020-07-16
1 前言
儘管簡單工廠模式實現了物件的建立和使用分離,但是仍然存在以下兩個問題:
- 工廠類過於龐大,包含了大量的判斷程式碼,導致維護和測試難度增大
- 系統擴充套件不靈活,如果增加了新的產品型別,必須修改靜態工廠方法的業務邏輯,違反了開閉原則
- 具體產品與工廠類之間的耦合度高,嚴重影響了系統的靈活性和擴充套件性
一個更好的辦法是使用工廠方法模式。
2 工廠方法模式
工廠方法模式:定義一個用於建立物件的介面,讓子類決定將哪一個類例項化。
工廠方法又簡稱工廠模式或虛擬構造器模式或多型工廠模式,讓一個類的例項化延遲到其子類,是一種類建立型模式。
結構圖如下:
工廠方法模式包含以下四個角色:
- Product(抽象產品):定義產品的介面,是工廠方法模式所建立的超型別,也就是產品物件的公共父類
- ConcreteProduct(具體產品):實現了抽象產品介面,某種型別的具體產品由專門的具體工廠建立,具體工廠與具體產品一一對應
- Factory(抽象工廠):在抽象工廠類中,聲明瞭工廠方法,用於返回一個產品。抽象工廠是工廠方法模式的核心,所有建立物件的工廠類都必須實現該介面
- ConcreteFactory(具體工廠):它是抽象工廠類的子類,實現了抽象工廠中定義的工廠方法,並可由客戶端呼叫,返回一個具體產品類的例項
3 例項
日誌記錄器的設計:該記錄器可以通過多種途徑儲存系統的執行日誌,例如檔案記錄或者資料庫記錄。
程式碼如下:
public class Test { public static void main(String[] args) { LoggerFactory factory = new FileLoggerFactory(); Logger logger = factory.createLogger(); logger.log(); } } //抽象產品 interface Logger { void log(); } //具體產品:DatabaseLogger class DatabaseLogger implements Logger { public void log() { System.out.println("資料庫日誌記錄"); } } //具體產品:FileLogger class FileLogger implements Logger { public void log() { System.out.println("檔案日誌記錄"); } } //抽象工廠 interface LoggerFactory { Logger createLogger(); } //具體工廠:DatabaseLoggerFactory class DatabaseLoggerFactory implements LoggerFactory { public Logger createLogger() { return new DatabaseLogger(); } } //具體工廠:FileLoggerFactory class FileLoggerFactory implements LoggerFactory { public Logger createLogger() { return new FileLogger(); } }
4 隱藏
可以把抽象工廠設定為抽象類,工廠方法直接可以對客戶端隱藏,也就是說可以直接通過抽象工廠呼叫具體產品類的業務方法,客戶端無需建立具體產品,直接通過工廠類呼叫即可,程式碼修改如下(抽象產品以及具體產品類不用修改):
//抽象工廠 abstract class LoggerFactory { public void log() { this.createLogger().log(); } public abstract Logger createLogger(); } //具體工廠:DatabaseLoggerFactory class DatabaseLoggerFactory extends LoggerFactory { public Logger createLogger() { return new DatabaseLogger(); } } //具體工廠:FileLoggerFactory class FileLoggerFactory extends LoggerFactory { public Logger createLogger() { return new FileLogger(); } } public class Test { public static void main(String[] args) { LoggerFactory factory = new FileLoggerFactory(); factory.log(); } }
5 主要優點
- 封裝細節:工廠方法用來建立客戶所需要的產品,同時還向客戶隱藏了哪種具體產品類將被例項化這一細節,使用者只需關心所需產品對應的工廠,無需關心建立細節,甚至無須知道具體產品類的類名
- 多型:工廠方法的多型效能夠讓工廠可以自主確定建立何種產品物件,而如何建立物件的細節則完全封裝在具體工廠內部
- 擴充套件性好:加入新產品時無須修改抽象工廠,抽象產品的介面,也無須修改客戶端與其他的具體產品和具體工廠,只需要增加一個具體工廠以及具體產品,系統擴充套件性很好,完全符合開閉原則
6 主要缺點
- 類數量多:在新增新產品時,需要編寫新的具體產品類,而且還要提供與之對應的具體工廠類,系統中類的個數將成對增加,一定程度上增加了系統的複雜度,有更多的類需要編譯和執行,給系統帶來額外開銷
- 增加理解難度:基於系統的擴充套件性需要引入抽象層,在客戶端中均使用了抽象層的定義,增加了系統的抽象性以及理解難度
7 適用場景
- 客戶端不知道其所需要的物件的類:在工廠方法模式中,客戶端不需要知道具體的產品類名,只需要知道所對應的工廠即可
- 抽象工廠類通過子類來指定建立哪個物件:工廠方法模式中,抽象工廠類只需要提供一個建立產品的介面,而有其子類來確定具體要建立的物件,利用面向物件的多型性和里氏代換原則,在程式執行時,子類物件將覆蓋父類物件,從而使得系統更加容易擴充套件