簡單工廠模式、工廠方法模式、抽象工廠模式,都是屬於建立型設計模式。嚴格上來講,簡單工廠模式不屬於23設計模式之一,由於它違背了開閉原則。java
這三種設計模式,名字都包含「工廠」二字,若是沒有認真地對它們的設計思想、代碼進行認真比較,還真的很難區分出到底是哪種模式,不少開發者很容易混淆。設計模式
接下來,我就將這三種設計模式放在一篇文章,用C#來實現它們並放在一塊兒進行比較。app
想象一下,如今商場有不少賣不一樣口味的冰激凌攤位,每一個攤位的位置都不盡相同,每一個商家只賣一種口味,商家提供了製做冰激凌的全部原料,須要顧客本身去製做。這時,同伴三我的,你說你去買冰激凌,讓你們說說都想買什麼口味的冰激凌,最後三我的恰好喜歡的口味都不一樣,分別是蘋果味、香蕉味、橘子味。你們委託你去買,你就跑到了A攤位,本身調製起了一根(一個?)蘋果味的冰激凌,而後,你又跑到幾十米外另外一攤位去製做香蕉味冰激凌,最後又跑到另外一攤位去製做橘子味的冰激凌。終於買好了三根冰激凌,拿回去後,發現本身那杯蘋果味的已經融化了…若是,大家一行有十幾我的,每一個人須要的口味都不一樣呢?這樣是否是很麻煩?佈局
商場管理人員意識到了這個問題,想了一個方法。他將全部的口味的冰激凌攤位,所有集中到了商場入口處來賣,而且,訂購了一臺賣冰激凌的機器,機器上有一排按鈕,每一個按鈕表明一種口味的冰激凌,你想買哪種口味就點擊哪一個按鈕,機器內部就會本身去製做一根該口味的冰激凌,而後吐出該冰激凌給顧客。能夠發現,顧客只需按一個按鈕,根本不須要像以前那樣本身去製做冰激凌,機器製做冰激凌的過程對於顧客來講也是透明的。這種模式,就是咱們的 簡單工廠模式 ,而生產冰激凌的機器,就是咱們所說的 工廠 。spa
1. 首先定義一個冰激凌接口,裏邊只有一個方法,就是顯示是哪一種口味.net
/// <summary> /// 冰激凌接口 /// </summary> public interface IceCream { void Taste(); }
2.定義三個類,AppleIceCream、BananaIceCream、OrangeIceCream,並繼承上面的接口,實現其中的方法。顯示本身獨特的口味設計
/// <summary> /// 蘋果 /// </summary> public class AppleIceCream : IceCream { public void Taste() { Console.WriteLine("這是蘋果口味的冰激凌"); } } /// <summary> /// 香蕉 /// </summary> public class BananaIceCream : IceCream { public void Taste() { Console.WriteLine("這是香蕉口味的冰激凌"); } } /// <summary> /// 橘子 /// </summary> public class OrangeIceCream : IceCream { public void Taste() { Console.WriteLine("這是橘子口味的冰激凌"); } }
3.定義一個工廠類,用來製做不一樣口味的冰激凌code
/// <summary> /// 工廠(製做冰淇淋的機器) /// </summary> public class IceCreamFactory { public static IceCream creamIceCream(string taste) { IceCream iceCream = null; // 這裏咱們經過switch來判斷,具體制做哪種口味的冰激凌 switch (taste) { case "Apple": iceCream = new AppleIceCream(); break; case "Orange": iceCream = new OrangeIceCream(); break; case "Banana": iceCream = new BananaIceCream(); break; default: break; } return iceCream; } }
4.最後看一下客戶端的代碼對象
static void Main(string[] args) { IceCream appleIceCream = IceCreamFactory.creamIceCream("Apple"); appleIceCream.Taste();//這是蘋果口味的冰激凌
IceCream bananaIceCream = IceCreamFactory.creamIceCream("Banana"); bananaIceCream.Taste();//這是香蕉口味的冰激凌
IceCream orangeIceCream = IceCreamFactory.creamIceCream("Orange"); orangeIceCream.Taste();//這是橘子口味的冰激凌
Console.ReadKey(); }
運行結果以下:
能夠看到,簡單工廠模式確實很「簡單」。通常,簡單工廠方法模式中,工廠類中有一個方法,經過switch中不一樣的值或者if else語句來建立不一樣的對象並返回,一般這個方法是一個靜態方法,(順便一提:簡單工廠模式也被稱做「靜態工廠模式」)在客戶端直接調用工廠類的該方法就能夠。整個冰激凌的生產(建立不一樣口味冰激凌的過程)被這個工廠類封裝了,客戶端不用去關注這些細節。blog
用了簡單方法模式後,顧客們方便多了,想要哪一種口味的冰激凌就直接點一下按鈕便可直接購買。如今,該機器只能賣三種口味的冰激凌,並無知足不少顧客的需求,管理員打算再添加一種草莓味的冰激凌來知足更多顧客。問題來了,整個機器已經作成了,按鈕數目爲3也已經固定了,若是想要再添加一種口味,那麼就要打開機器內部,往裏邊添加製做草莓味冰激凌的原料以及製做工藝,還要在機器外部再增長一個按鈕。這可麻煩了,畢竟整個機器的佈局什麼的都固定下來了。
其實,這正是簡單工廠模式的缺點,其違背了開閉原則,擴展性差。觀察簡單工廠模式的工廠類代碼,咱們能夠發現,其內部作了不少邏輯的處理,經過switch值的不一樣來建立不一樣的對象。如今,若是要新增草莓味的冰激凌,首先要新增StrawberryIceCream,而且,還要在switch裏邊,新增一個case分支,來判斷是否生產StrawberryIceCream,因此不是很合理。
經過 工廠方法模式 ,咱們就能解決這一問題。仔細研究,之因此會產生上面的問題,是由於咱們只有一個「工廠」,不管何種口味的冰激凌生產,都交給這個工廠去處理致使的。那麼,如今,咱們能夠,設計多個「工廠」,每種工廠只負責生產一種口味的冰激凌。回到商場來,仍是在商場入場處,咱們購置多臺生產冰激凌的機器,每臺機器只能生產一種口味的冰激凌,每臺機器有一個按鈕,點擊下去就會吐出該口味冰激凌,而後將這些機器一個挨着一個排列起來就行。如今,若是要添加一種新的口味,那麼只要再購置一臺機器,而後挨着放進去便可。
接下來,看看具體的代碼實現:
1. 和簡單工廠模式同樣,先定義一個接口。再定義AppleIceCream、BananaIceCream和OrangeIceCream去實現這個接口(看上面1和2步驟)
2.定義工廠接口
/// <summary> /// 工廠模式接口 /// </summary> public interface IceCreamFactory { IceCream CreateIceCream(); }
3.再分別定義AppleIceCreamFactory、BananaIceCreamFactory、OrangeIceCreamFactory,繼承剛剛定義的工廠接口
/// <summary> /// 蘋果工廠 /// </summary> public class AppleIceCreamFactory : IceCreamFactory { public IceCream CreateIceCream() { return new AppleIceCream(); } } /// <summary> /// 香蕉工廠 /// </summary> public class BananaIceCreamFactory : IceCreamFactory { public IceCream CreateIceCream() { return new BananaIceCream(); } } /// <summary> /// 橘子工廠 /// </summary> public class OrangeIceCreamFactory : IceCreamFactory { public IceCream CreateIceCream() { return new OrangeIceCream(); } }
4.客戶端代碼
static void Main(string[] args) { //生產蘋果味冰激凌 IceCreamFactory appleFactory = new AppleIceCreamFactory(); IceCream appleIceCream = appleFactory.CreateIceCream(); appleIceCream.Taste(); //生產香蕉口味冰激凌 IceCreamFactory bananaFactory = new BananaIceCreamFactory(); IceCream bananaIceCream = bananaFactory.CreateIceCream(); bananaIceCream.Taste(); //生產橘子口味冰激凌 IceCream orangeIceCream = new OrangeIceCreamFactory().CreateIceCream(); orangeIceCream.Taste();
Console.ReadKey(); }
運行結果以下
能夠想象,不一樣人的需求是不一樣的,有的人吃冰激凌是當作飯後甜點,有的人直接把它當飯吃。所以,商場爲了讓顧客有多種選擇,想要對每種口味冰激凌的量進行分類,分爲大份和小份的。好比咱們以前生產的是大份的冰激凌,那麼要完成生產多種口味小份的冰激凌,能怎麼作呢?固然,商場能夠再購置蘋果味冰激凌(小份)、香蕉味冰激凌(小份)、橘子味冰激凌(小份)的機器,而後挨着放在以前幾臺旁邊。這種思路就是咱們上邊的工廠方法模式。但是,這樣就須要添加多了一倍的機器數量。想象一下,若是商場在一開始規劃的時候就已經打算賣兩種份量多種口味的冰激凌,那能怎麼作呢?
因爲每種口味的冰激凌,材料和製做工藝都是相同的,因此,咱們徹底能夠,每臺機器負責生產特定口味的冰激凌,並配備兩個按鈕,用來區分生產大份的或者是小份的,這樣是比較符合現實的。這就是咱們接下來要說的 抽象工廠模式。
1. 因爲要生產不一樣大小的冰激凌,因此,如今冰激凌的接口有兩個,分別是 BigIceCream 和 SmallIceCream
public interface BigIceCream { void Taste(); } public interface SmallIceCream { void Taste(); }
2.定義各個口味的冰激凌,繼承剛剛定義的接口,實現其方法
public class BigAppleIceCream : BigIceCream { public void Taste() { Console.WriteLine("這是蘋果味冰激凌(大份)"); } } public class SmallAppleIceCream : SmallIceCream { public void Taste() { Console.WriteLine("這是蘋果味冰激凌(小份)"); } }
//後邊還有四個類BigBananaIceCream、SmallBananaIceCream、BigOrangeIceCream、SmallOrangeIceCream
3.定義工廠接口,能夠看到,這裏有兩個方法,分別生產小份大的和大份的
/// <summary> /// 生產小份大的和大份的接口 /// </summary> public interface IceCreamFactory { BigIceCream CreateBigIceCream(); SmallIceCream CreateSmallIceCream(); }
4.定義三個工廠類繼承上邊的接口並實現其方法
public class AppleIceCreamFactory : IceCreamFactory { public BigIceCream CreateBigIceCream() { return new BigAppleIceCream(); } public SmallIceCream CreateSmallIceCream() { return new SmallAppleIceCream(); } }
//這裏是蘋果味的大份和小份,香蕉和橘子按一樣的方法添加
5.客戶端代碼
/// <summary> /// 抽象工廠模式 /// </summary> /// <param name="args"></param> static void Main(string[] args) { //生產蘋果味冰激凌 IceCreamFactory appleIceCreamFactory = new AppleIceCreamFactory(); BigIceCream appleBigIceCream = appleIceCreamFactory.CreateBigIceCream(); SmallIceCream appleSmallIceCream = appleIceCreamFactory.CreateSmallIceCream(); appleBigIceCream.Taste(); appleSmallIceCream.Taste(); Console.ReadKey(); }
運行結果以下
能夠看到,之因此叫抽象工廠,是由於和工廠方法相比,這裏有多個抽象產品類存在(即大份的冰激凌和小份的冰激凌),每一個抽象產品類能夠派生出多個具體的產品,生產的是系列產品,其工廠接口相對於工廠方法模式而言,是有多個方法的,用來生產不一樣的抽象產品。
不過,咱們也很容易看出,抽象工廠模式的弊端。好比如今,商場想要提供的是大、中、小三種系列產品,那麼如今,須要改動的代碼就有點多了。首先須要建立一個接口,用來生產中份的冰激凌,而後還要實現具體的類,還須要修改工廠接口,並修改具體的工廠類。
經過UML圖以及代碼不難對三種工廠模式進行一個區分。簡單工廠模式,工廠類是整個模式的關鍵所在,包含了必要的邏輯判斷,可以外界給定的信息, 決定究竟建立哪一個具體類的對象。工廠方法模式 是對簡單工廠方法模式的一個抽象,抽離出了一個Factory類(或者接口),這個接口不負責具體產品的生產,而只是指定一些規範,具體的生產工做由其子類去完成。這個模式中,工廠類和產品類每每是一一對應的,徹底解決了簡單工廠模式中違背「開閉原則」的問題,實現了可擴展;抽象工廠模式 的特色是存在多個抽象產品類,每一個抽象產品類能夠派生出多個具體產品類,工廠提供多種方法,去生產「系列」產品。
簡單工廠模式適用於工廠類須要建立的對象比較少的狀況,客戶只須要傳入具體的參數,就能夠忽略工廠的生產細節,去獲取想要的對象;
工廠方法模式,主要是針對單一產品結構的情景;
抽象工廠模式則是針對多級產品結構(系列產品)的一種工廠模式。
最後在說一下,每種模式都有本身的優勢和弊端,沒有最好的模式,只有最適合的模式,只要符合實際開發需求就是最好的。
原文連接:http://www.javashuo.com/article/p-eydoooee-dc.html
原文是用java實現的,我這裏是用C#實現的