設計模式系列之一:簡單工廠模式
- 2020 年 6 月 25 日
- 筆記
- Design pattern, 簡單工廠模式, 設計模式
1.1 定義
簡單工廠模式屬於創建型模式,又稱為靜態工廠方法模式,在簡單工廠模式中,可以根據參數的不同,來返回不同類的實例,簡單工廠模式專門定義一個類來負責創建子類的實例,被創建的類通常有一個共同的父類
1.2 簡單工廠模式結構圖(簡版)
Factory:工廠類,簡單工廠模式的核心,它負責實現創建所有實例的內部邏輯。工廠類的創建產品類的方法可以被外界直接調用,創建所需的產品對象
IProduct:抽象產品類,簡單工廠模式所創建的所有對象的父類,它負責描述所有實例所共有的公共介面
Product:具體產品類,是簡單工廠模式的目標類
1.3 簡單工廠的實現一
假設有一個電腦的代工生產商,它目前已經可以代工生產聯想電腦了,隨著業務的拓展,這個代工生產商還要生產惠普和mac電腦;
這樣我們就需要用一個單獨的類來專門生產電腦,這就用到了簡單工廠模式,同時用到了繼承、封裝、多態等面向對象編程的思想,下面我們來實現簡單工廠模式
1.3.1 產品抽象類
public abstract class Computer { /** * 產品的抽象方法,由具體的產品類去實現 */ public abstract void start(); }
1.3.2 具體實現類
public class LenovoComputer extends Computer { @Override public void start() { System.out.println("lenovo computer run"); } }
public class MacComputer extends Computer { @Override public void start() { System.out.println("Mac computer run"); } }
public class HpComputer extends Computer { @Override public void start() { System.out.println("hp computer run"); } }
1.3.3 工廠類
public class ComputerFactory { public static Computer createComputer(String type) { Computer computer = null; switch (type) { case "lenovo": computer = new LenovoComputer(); break; case "hp": computer = new HpComputer(); break; case "Mac": computer = new MacComputer(); break; default: break; } return computer; } }
1.3.4 UML類圖
1.4 優缺點
優點:
1. 工廠類含有必要的判斷邏輯,可以決定在什麼時候創建哪一個產品類的實例,客戶端可以免除直接創建產品對象的責任,而僅僅「消費」產品;實現了對責任的分割,它提供了專門的工廠類用於創建對象。
2. 客戶端無須知道所創建的具體產品類的類名,只需要知道具體產品類所對應的參數即可,對於一些複雜的類名,通過簡單工廠模式可以減少使用者的記憶量。
3. 通過引入配置文件,可以在不修改任何客戶端程式碼的情況下更換和增加新的具體產品類,在一定程度上提高了系統的靈活性。
缺點:
1. 由於工廠類集中了所有產品創建邏輯,一旦不能正常工作,整個系統都要受到影響。
2. 使用簡單工廠模式將會增加系統中類的個數,在一定程式上增加了系統的複雜度和理解難度。
3. 系統擴展困難,一旦添加新產品就不得不修改工廠邏輯,同樣破壞了「開閉原則」;在產品類型較多時,有可能造成工廠邏輯過於複雜,不利於系統的擴展和維護。
4. 簡單工廠模式由於使用了靜態工廠方法,造成工廠角色無法形成基於繼承的等級結構
1.5 適用場景
1. 工廠類負責創建的對象比較少:由於創建的對象較少,不會造成工廠方法中的業務邏輯太過複雜。
2. 客戶端只知道傳入工廠類的參數,對於如何創建對象不關心:客戶端既不需要關心創建細節,甚至連類名都不需要記住,只需要知道類型所對應的參數。
1.6 模式應用
1. JDK類庫中廣泛使用了簡單工廠模式,如工具類java.text.DateFormat,它用于格式化一個本地日期或者時間
public final static DateFormat getDateInstance(); public final static DateFormat getDateInstance(int style); public final static DateFormat getDateInstance(int style,Locale locale);2. 獲取不同加密演算法的密鑰生成器
KeyGenerator keyGen=KeyGenerator.getInstance("DESede");
1.7 開閉原則
對於上面兩種簡單工廠模式的實現方法,如果我們要添加新的 parser,那勢必要改動到 RuleConfigParserFactory 的程式碼,那這是不是違反開閉原則呢?
實際上,如果不是需要頻繁地添加新的 parser,只是偶爾修改一下 RuleConfigParserFactory 程式碼,稍微不符合開閉原則,也是完全可以接受的。
儘管簡單工廠模式的程式碼實現中,有多處 if 分支判斷邏輯,違背開閉原則,但權衡擴展性和可讀性,這樣的程式碼實現在大多數情況下(比如,不需要頻繁地添加 parser,也沒有太多的 parser)是沒有問題的