.NET設計模式(1): 簡單工廠模式
最近一直在看設計模式,想把自己的學習筆記與大家分享一下,如果能幫助大家的話,我會非常高興,同時也歡迎大家指出裏面的不足。園子裏其實關於此類文章已經很多了,如果dudu感覺放在首頁欠妥的話,可以調一下。
簡單工廠模式(Simple Factory Pattern)
介紹:簡單工廠模式不能說是一個設計模式,說它是一種編程習慣可能更恰當些。因爲它至少不是Gof23種設計模式之一。但它在實際的編程中經常被用到,而且思想也非常簡單,可以說是工廠方法模式的一個引導,所以我想有必要把它作爲第一個講一下。
引入:
我們在編程的時候,每當"new"一個對象之後,這個對象就依賴於這個類了。如果在後期的維護過程中由於某些原因需要修改一下這個類,則唯一的做法就是打開源代碼,進行修改,修改所有與這個對象有關的操作。這對我們是非常不利的。
問題出來了:對象不能應對“具體實例化類型”的變化
解決思路:套用一下李建忠李老師的話,封裝變化點,哪裏變化,封裝哪裏。在這個例子中,要實例化的類變了,就將實例化這個操作封裝起來,我們可以把"new"這個操作移交一個具體的類,由它去負責根據我們的條件創建具體類的實例,也就是下面要說的“簡單工廠模式”。
定義:
專門定義一個類來負責創建其他類的實例,被創建的實例通常都具有共同的父類或接口。簡單工廠模式又稱爲靜態工廠方法(Static Factory Method)模式,屬於類的創建型模式,通常根據一個條件(參數)來返回不同的類的實例。
意圖:
提供一個類,由它負責根據一定的條件創建某一具體類的實例
參與者:
- 工廠角色(Creator)
是簡單工廠模式的核心,它負責實現創建所有具體產品類的實例。工廠類可以被外界直接調用,創建所需的產品對象。 - 抽象產品角色(Product)
是所有具體產品角色的父類,它負責描述所有實例所共有的公共接口。 - 具體產品角色(Concrete Product)
繼承自抽象產品角色,一般爲多個,是簡單工廠模式的創建目標。工廠類返回的都是該角色的某一具體產品。
UML圖:
現實生活中例子:
每次參加不同的聚會或者與不同的人見面,可能穿的衣服是不一樣的,比如,你今天上午要與你的一個新客戶見面,你可能會對你的老婆說:老婆,給拿件商務裝(參數),我要去見我的一個客戶,你老婆(工廠類)接到你的請求(商務裝參數)後,從衣櫃中取出一件商務裝(具體產品),交給你。整個過程就完成了。
分析:
你可能根據不同的條件,要的衣服是不一樣的,但要的衣服都是已經在你的衣櫃中存在的。並且,每件上衣它們都屬於同一種抽象,即它們可以從一個抽象類或接口中繼承,這此衣服各自都有一定特徵,這些都是條件。然後你要的時候,就可以向你老婆說一種特徵,她就會根據這個特徵爲你服務了。這就是典型的簡單工廠模式的應用。
抽象產品類代碼
2 /// 抽象產品類:上衣
3 /// </summary>
4 public interface ICoat
5 {
6 void GetYourCoat();
7 }
非常簡單,是吧?這裏我只是舉一個僅僅能說明問題的例子,在具體的項目中,可能是很複雜的哦。。
具體產品類代碼
2{
3 /// <summary>
4 /// 具體產品類:商務上衣
5 /// </summary>
6 public class BusinessCoat:ICoat
7 {
8 public void GetYourCoat()
9 {
10 Console.WriteLine("商務上衣");
11 }
12 }
13
14 /// <summary>
15 /// 具體產品類:時尚上衣
16 /// </summary>
17 public class FashionCoat : ICoat
18 {
19 /// <summary>
20 /// 實現ICoat中定義的方法
21 /// </summary>
22 /// <returns></returns>
23 public void GetYourCoat()
24 {
25 Console.WriteLine("時尚上衣");
26 }
27 }
28}
簡單工廠模式中最核心的部分:工廠類
2{
3 /// <summary>
4 /// 簡單工廠模式中的核心部分:工廠類
5 /// </summary>
6 public class Factory
7 {
8 public ICoat CreateCoat(string styleName)
9 {
10 switch (styleName.Trim().ToLower())
11 {
12 case "business":
13 return new BusinessCoat();
14 case "fashion":
15 return new FashionCoat();
16 default :
17 throw new Exception("還沒有你要的那種衣服");
18 }
19 }
20 }
21}
再看一下客戶在調用的時候的代碼
2 /// 客戶類
3 /// </summary>
4 class Client
5 {
6 static void Main(string[] args)
7 {
8 ICoat food;
9 try
10 {
11 Factory factory = new Factory();
12
13 Console.Write("我要的是時尚上衣/t");
14 food = factory.CreateCoat("fashion");
15 food.GetYourCoat();
16
17 }
18 catch (Exception ex)
19 {
20 Console.WriteLine(ex.Message);
21 }
22 }
23 }
到這裏,代碼就完成了。
在客戶端的代碼中有我們就可以根據具體的參數,返回我們希望返回的對象,將"new"操作推遲到工廠類中實現。
這裏,參數我直接寫上了,我們其實可以將這個參數寫到一個xml文件中,如app.config文件中,動態的讀出來,需要穿另外一種衣服了,只需要打開app.config文件,修改裏面的值就行了,不需要項目重新編譯。這樣這個小程序就能夠適應一定的變化了(在上傳上去的代碼中我會修改一下)。其實它也是設計模式正要解決的問題,在不修改代碼的情況下,使項目能夠適應一定的客戶需求變化。注意,是一定的,並非全部。
優點:
- 簡單工廠模式能夠根據外界給定的信息,決定究竟應該創建哪個具體類的對象。通過它,外界可以從直接創建具體產品對 象的尷尬局面中擺脫出來。
- 外界與具體類隔離開來,偶合性低。
- 明確區分了各自的職責和權力,有利於整個軟件體系結構的優化。
缺點:
- 工廠類集中了所有實例的創建邏輯,容易違反GRASPR的高內聚的責任分配原則
- 雖然簡單工廠模式能夠適應一定的變化,但是它所能解決的問題是遠遠有限的。它所能創建的類只能是事先教考慮到的,如果需要添加新的類,則就需要改變工廠類了。(這個問題在下一個工廠方法模式將得到很好的解決)
應用情景
- 工廠類負責創建的對象比較少
- 客戶只知道傳入了工廠類的參數,對於始何創建對象(邏輯)不關心
參考資料
- 《深入淺出設計模式(C#/Java版) 》 清華大學出版社
- MSDN Webcast C#面向對象設計模式縱橫談 李建忠老師
很好的一篇文章,很清楚明瞭解釋了簡單工廠的實現原理和思路,謝謝。