介紹
簡單工廠模式不能說是一個設計模式,說它是一種編程習慣可能更恰當些。因為它至少不是Gof23種設計模式之一。但它在實際的編程中經常被用到,而且思想也非常簡單,可以說是工廠方法模式的一個引導,所以我想有必要把它作為第一個講一下。
模式動機
考慮一個簡單的軟件應用場景,一個軟件系統可以提供多個外觀不同的按鈕(如圓形按鈕、矩形按鈕、菱形按鈕等),這些按鈕都源自同一個基類,不過在繼承基類后不同的子類修改了部分屬性從而使得它們可以呈現不同的外觀,如果我們希望在使用這些按鈕時,不需要知道這些具體按鈕類的名字,只需要知道表示該按鈕類的一個參數,並提供一個調用方便的方法,把該參數傳入方法即可返回一個相應的按鈕對象,此時,就可以使用簡單工廠模式。
模式定義
簡單工廠模式(Simple Factory Pattern):又稱為靜態工廠方法(Static Factory Method)模式,它屬於類創建型模式。在簡單工廠模式中,可以根據參數的不同返回不同類的實例。簡單工廠模式專門定義一個類來負責創建其他類的實例,被創建的實例通常都具有共同的父類。
模式結構
簡單工廠模式包含如下角色:
Factory:工廠角色
Product:抽象產品角色
ConcreteProduct:具體產品角色
工廠角色(Creator) |
是簡單工廠模式的核心,它負責實現創建所有具體產品類的實例。工廠類可以被外界直接調用,創建所需的產品對象。 |
抽象產品角色(Product)
|
是所有具體產品角色的父類,它負責描述所有實例所共有的公共接口。
|
具體產品角色(Concrete Product)
|
繼承自抽象產品角色,一般為多個,是簡單工廠模式的創建目標。工廠類返回的都是該角色的某一具體產品。
|
UML圖
現實生活中例子
每次參加不同的聚會或者與不同的人見面,可能穿的衣服是不一樣的,比如,你今天上午要與你的一個新客戶見面,你可能會對你的老婆說:老婆,給拿件商務裝(參數),我要去見我的一個客戶,你老婆(工廠類)接到你的請求(商務裝參數)后,從衣櫃中取出一件商務裝(具體產品),交給你。整個過程就完成了。
你可能根據不同的條件,要的衣服是不一樣的,但要的衣服都是已經在你的衣櫃中存在的。並且,每件上衣它們都屬於同一種抽象,即它們可以從一個抽象類或接口中繼承,這此衣服各自都有一定特征,這些都是條件。然后你要的時候,就可以向你老婆說一種特征,她就會根據這個特征為你服務了。這就是典型的簡單工廠模式的應用。
模式實例與解析
Product:抽象產品角色 ICoat.cs
namespace SimpleFactory { /// <summary> /// 抽象產品類:上衣 /// </summary> public interface ICoat { void GetYourCoat(); } }
ConcreteProduct:具體產品角色
BusinessCoat.cs
using System; namespace SimpleFactory { /// <summary> /// 具體產品類:商務上衣 /// </summary> public class BusinessCoat : ICoat { public void GetYourCoat() { Console.WriteLine("商務上衣"); } } }
FashionCoat.cs
using System; namespace SimpleFactory { /// <summary> /// 具體產品類:時尚上衣 /// </summary> public class FashionCoat : ICoat { public void GetYourCoat() { Console.WriteLine("時尚上衣"); } } }
Factory:工廠角色 Factory.cs
using System; namespace SimpleFactory { /// <summary> /// 簡單工廠模式中的核心部分:工廠類 /// </summary> public class Factory { public ICoat CreateCoat(string styleName) { switch (styleName.Trim().ToLower()) { case "business": //商務上衣 return new BusinessCoat(); case "fashion"://時尚上衣 return new FashionCoat(); default: throw new Exception("還沒有你要的那種衣服"); } } } }
Program.cs
using System; namespace SimpleFactory { /// <summary> /// 客戶類 /// </summary> class Client { static void Main(string[] args) { ICoat food; try { Factory factory = new Factory(); Console.Write("請選擇:時尚上衣 fashion,商務上衣 business\t"); string choice = Console.ReadLine(); switch (choice) { case "fashion"://時尚上衣 Console.Write("我要的是時尚上衣\t"); food = factory.CreateCoat("fashion"); food.GetYourCoat(); break; case "business": //商務上衣 Console.Write("我要的是商務上衣\t"); food = factory.CreateCoat("business"); food.GetYourCoat(); break; default: Console.Write("還沒有你要的那種衣服\t"); break; } Console.ReadLine(); } catch (Exception ex) { Console.WriteLine(ex.Message); } } } }
體系結構
模式分析
將對象的創建和對象本身業務處理分離可以降低系統的耦合度,使得兩者修改起來都相對容易。
在調用工廠類的工廠方法時,由於工廠方法是靜態方法,使用起來很方便,可通過類名直接調用,而且只需要傳入一個簡單的參數即可,在實際開發中,還可以在調用時將所傳入的參數保存在XML等格式的配置文件中,修改參數時無須修改任何源代碼。
簡單工廠模式最大的問題在於工廠類的職責相對過重,增加新的產品需要修改工廠類的判斷邏輯,這一點與開閉原則是相違背的。
簡單工廠模式的要點在於:當你需要什么,只需要傳入一個正確的參數,就可以獲取你所需要的對象,而無須知道其創建細節。
模式優缺點
- 簡單工廠模式的優點
工廠類含有必要的判斷邏輯,可以決定在什么時候創建哪一個產品類的實例,客戶端可以免除直接創建產品對象的責任,而僅僅“消費”產品;簡單工廠模式通過這種做法實現了對責任的分割,它提供了專門的工廠類用於創建對象。
客戶端無須知道所創建的具體產品類的類名,只需要知道具體產品類所對應的參數即可,對於一些復雜的類名,通過簡單工廠模式可以減少使用者的記憶量。
通過引入配置文件,可以在不修改任何客戶端代碼的情況下更換和增加新的具體產品類,在一定程度上提高了系統的靈活性。
- 簡單工廠模式的缺點
由於工廠類集中了所有產品創建邏輯,一旦不能正常工作,整個系統都要受到影響。
使用簡單工廠模式將會增加系統中類的個數,在一定程序上增加了系統的復雜度和理解難度。
系統擴展困難,一旦添加新產品就不得不修改工廠邏輯,在產品類型較多時,有可能造成工廠邏輯過於復雜,不利於系統的擴展和維護。
簡單工廠模式由於使用了靜態工廠方法,造成工廠角色無法形成基於繼承的等級結構。
模式適用環境
在以下情況下可以使用簡單工廠模式:
工廠類負責創建的對象比較少:由於創建的對象較少,不會造成工廠方法中的業務邏輯太過復雜。
客戶端只知道傳入工廠類的參數,對於如何創建對象不關心:客戶端既不需要關心創建細節,甚至連類名都不需要記住,只需要知道類型所對應的參數。
小結
創建型模式對類的實例化過程進行了抽象,能夠將對象的創建與對象的使用過程分離。
簡單工廠模式又稱為靜態工廠方法模式,它屬於類創建型模式。在簡單工廠模式中,可以根據參數的不同返回不同類的實例。簡單工廠模式專門定義一個類來負責創建其他類的實例,被創建的實例通常都具有共同的父類。
簡單工廠模式包含三個角色:工廠角色負責實現創建所有實例的內部邏輯;抽象產品角色是所創建的所有對象的父類,負責描述所有實例所共有的公共接口;具體產品角色是創建目標,所有創建的對象都充當這個角色的某個具體類的實例。
簡單工廠模式的要點在於:當你需要什么,只需要傳入一個正確的參數,就可以獲取你所需要的對象,而無須知道其創建細節。
簡單工廠模式最大的優點在於實現對象的創建和對象的使用分離,將對象的創建交給專門的工廠類負責,但是其最大的缺點在於工廠類不夠靈活,增加新的具體產品需要修改工廠類的判斷邏輯代碼,而且產品較多時,工廠方法代碼將會非常復雜。
簡單工廠模式適用情況包括:工廠類負責創建的對象比較少;客戶端只知道傳入工廠類的參數,對於如何創建對象不關心。