說起軟件架構中的設計模式,大多數人肯定第一句就是,工廠模式。准確講經典24個設計模式中沒有工廠模式,而是簡單工廠模式,工廠方法模式和抽象工廠模式這三種,三種互相有本質區別,各自為解決不同領域的問題,而形成的一套代碼體系。我記得我畢業后第一份工作跳槽的時候,遇到的一次面試就有設計模式題目,不過當時太嫩,大敗而歸,也是那時知道有設計模式這個東東,因為這個學校是不教的。從此也就對設計模式就開始去研究啦,於是就有了這個系列的文章。
面向對象編程的三大基本特性:封裝、繼承、多態。簡簡單單的概念,其實每一個特性都能拓展得很深很深。這里我們只看下多態,多態就是利用了繼承的概念,抽象依賴實現,可以看一個大家在學習編程語言啟蒙的時候都會遇到的一個實例,首先創建一個基類,用接口也可以,里面放一個方法。
創建SampleBase類,代碼如下:
1 public class SampleBase { 2 3 public String getName() 4 { 5 return this.getClass().toString(); 6 } 7 }
再創建一個集成該類的衍生類,代碼如下:
1 public class SampleImpl extends SampleBase { 2 @Override 3 public String getName() 4 { 5 return this.getClass().toString(); 6 } 7 }
在測試類中進行測試,測試代碼如下:
public static void main(String[] args) { SampleBase base = new SampleImpl(); System.out.println(base.getName()); }
運行結果:
class com.aspnetdream.test.SampleImpl
其實對於這個情況,我腦海中一直記得一句話,基類指針指向子類應用,我的學習生涯接觸這個最開始是在C++的語言中學習的,記住這句話,應對繼承和多態我覺得是萬能的法寶。基於編程語言這么一個優秀的特質,再想想在工作中遇到的很多應用場景,我曾經開發一個餐飲的ERP系統,在處理訂單的時候,很多不同的單據,這些單據有相通之處,也會有各自不同點,比如配料訂單和退貨訂單,這兩種訂單,相同的地方是對業務單據的物料拆分處理是一樣的,但最后訂單存儲的表是不一樣的,也就是說,兩個單據我在拆分處理需要一樣的代碼,但在這一步完成之后,又各自走向不同的代碼,好,套用簡單工廠模式來解決。
創建單據基類IOrderInfo,我在這里把他定義成了一個接口,實際應用中可以定義為抽象類,甚至就是一個類。
創建IOrderInfo 接口,代碼如下:
1 //簡單工廠模式接口定義層 2 public interface IOrderInfo { 3 public String getOrderInfo(); 4 }
窗建完接口,我們分別創建配料單和退貨單的衍生類。
配料單類OrderMakeCustom,代碼如下:
1 //簡單工程接口實現層 消耗訂單操作類 2 public class OrderMakeCustom implements IOrderInfo { 3 4 public String getOrderInfo() 5 { 6 return this.getClass().toString(); 7 } 8 9 }
退貨單類 OrderReturnCustom,代碼如下:
//簡單工廠接口實現層 退貨訂單操作類 public class OrderReturnCustom implements IOrderInfo { public String getOrderInfo() { return this.getClass().toString(); } }
兩個衍生類都實現IOrderInfo接口,寫到這里稍微有經驗點的同學就可以看出來,在實際代碼調用中就可以
IOrderInfo order = new OrderMakeCustom();
不錯可以這么做,這是比較粗暴的做法,但現實在項目開發的時候,這樣的代碼卻比比皆是。
我們這里使用簡單工廠來實現,把new的任務交給工廠來完成,將new的任務交給工廠而不是在具體的業務流程代碼中去完成,我個人任務有一下幾點好處:
1、代碼的整潔度,易於維護,如果整篇代碼摻雜很多的new,我想讀代碼的人是相當痛苦的,這種流線型的代碼方式,帶來的惡果就是,業務一復雜,大家就開始走迷宮。
2、將代碼放入工廠中,可以為后續代碼升級做准備,如果,我將對應的接口實現的所有子類對應的放入一個xml文件中,用反射來實例化一個具體的基類的,這是不是就是IOC的原型啦。
繼續代碼,創建一個Factory,在這個類中就是根據不同業務流程,創建不同訂單實例交給調用方,實現代碼:
1 public class Factory { 2 3 //簡單工廠模式 創建實現操作類工廠 4 public static IOrderInfo createOrderInfo(EServiceType createType) 5 { 6 switch(createType) 7 { 8 case Make: 9 return new OrderMakeCustom(); 10 case Return: 11 return new OrderReturnCustom(); 12 default: 13 return null; 14 15 } 16 } 17 }
為了便於創建我這里放了一個枚舉類型,簡單工廠的工廠類根據傳入的不同枚舉類型,闖將不同的實例類。
OK,到這里一個簡單工廠模式就搭建完成了,我們來測試運行,測試代碼如下:
1 public static void main(String[] args) { 2 3 SampleBase base = new SampleImpl(); 4 System.out.println(base.getName()); 5 6 //根據不同的類型實例化不同的訂單操作類 7 //------簡單工廠模式(靜態工廠模式) 8 //退貨訂單操作類 9 IOrderInfo order = Factory.createOrderInfo(EServiceType.Return); 10 //獲取訂單后,處理訂單 11 getOrderInfo(order); 12 13 order = Factory.createOrderInfo(EServiceType.Make); 14 getOrderInfo(order); 15 16 } 17 18 //實際項目中對訂單模型進行操作,而不用關注是那種類型訂單,在業務實現層去關注返回什么樣的訂單 19 private static void getOrderInfo(IOrderInfo order) 20 { 21 System.out.println(order.getOrderInfo()); 22 }
運行結果:
class com.aspnetdream.bussinessImpl.OrderReturnCustom class com.aspnetdream.bussinessImpl.OrderMakeCustom
使用抽象層IOrderInfo對象作為句柄,具體實現看不同的業務要求去工廠請求相應的實現層。再回到我最開始描述的場景,對兩種單據中相同的業務我們可以放入抽象層,甚至在抽象層我們可以定義不同的業務代碼相同的調用方法,這樣你的代碼檔次就會被拉高很多很多!簡單工廠模式也叫靜態工廠模式,它創建實現層的方式較為呆板,只是把new的代碼都放入了工廠中,但你依然需要使用選擇模式,也就是告訴工廠你是創建A,還是創建B,這就是我代碼中加入枚舉的原因了,這其實在代碼本質上和new 一個具體實現沒有太大的區別。所以,由此就產生了工廠方法模式。對於這個模式的應用在我的印象中是基於不同的產品操作而想到的,在開發一個POS后端應用時,都是產品信息,但是交給POS端和交給手機移動端的信息是不一樣的,POS端也許信息比較全面,交給移動端信息比較少,因為在我這個產品中,移動端僅限於看報表。這里我們嘗試着用工廠方法模式來解決這個問題。
首先創建產品的基類,iproduct接口,代碼如下:
1 //工廠方法模式---抽象角色接口 2 public interface iproduct { 3 4 public String getPrdName(); 5 }
再分別創建Pos和移動端不同的產品實現類,PosProduct和MobileProduct類,代碼實現:
//工廠方法模式 具體角色類 public class MobileProduct implements iproduct { //實現抽象角色接口 @Override public String getPrdName() { return this.getClass().toString(); } } //工廠方法模式---具體角色類 public class PosProduct implements iproduct { @Override public String getPrdName() { return this.getClass().toString(); } }
基於應用角色我們就創建完了,使用工廠模式,肯定需要創建工廠嘛,創建產品抽象工廠IProductFactory,代碼如下:
//工廠方法模式 ---- 抽象工廠 public abstract class IProductFactory { public abstract iproduct getProduct(); }
抽象工廠負責返回抽象角色,抽象對抽象。
有抽象就有實現,我們需要操作POS和Mobile端不同的產品信息,如是,針對抽象我們有2個不同業務實現要求,那么實現抽象來創建這2個實現工廠PosFactory和MobileFactory,代碼如下:
1 //工廠方法模式 ----具體角色工廠 pos產品工廠 2 public class PosFactory extends IProductFactory { 3 4 public iproduct getProduct() 5 { 6 return new PosProduct(); 7 } 8 9 } 10 11 12 //工廠方法模式---工廠方法模式 具體產品共 移動類產品工廠類 13 public class MobileFactory extends IProductFactory { 14 15 public iproduct getProduct() 16 { 17 return new MobileProduct(); 18 } 19 20 }
創建完這一步其實基本的工廠方法模式也就完成了,接下來我們測試,測試代碼如下:
1 public static void main(String[] args) { 2 3 //------工廠方法模式 4 IProductFactory ifactory = new MobileFactory();//移動端類產品工廠 返回移動端產品 5 iproduct prd= ifactory.getProduct(); 6 System.out.println(prd.getPrdName()); 7 8 ifactory = new PosFactory();//返回pos類產品工廠 返回pos類產品 9 prd = ifactory.getProduct(); 10 System.out.println(prd.getPrdName()); 11 12 } 13 14 //實際項目中對訂單模型進行操作,而不用關注是那種類型訂單,在業務實現層去關注返回什么樣的訂單 15 private static void getOrderInfo(IOrderInfo order) 16 { 17 System.out.println(order.getOrderInfo()); 18 }
運行結果:
class com.aspnetdream.driver.productImpl.MobileProduct class com.aspnetdream.driver.productImpl.PosProduct
工廠方法模式,在我的記憶中就是抽象對抽象,實現對實現,實現多少依據具體的業務需求來完成,可以無限的實現下去,當然,你就需要無限的工廠來幫你實現。
簡單工廠模式和工廠方法模式比較分析:
在我看來,簡單工廠模式就是工廠模式中的屌絲,工廠方法模式就是高富帥,屌絲的最大特點就是,“躲進小樓成一統,管他春夏與秋冬”,外部怎么弄的我不管,你給讓我創建什么類型,我創建好給你就行,同時你也必須將需要創建的類型寫入工廠中,也就是new一個實例。
然而,高富帥的工廠方法模式,有娘生也有娘養,首先在工廠的抽象層,你就必須要對應你這個工廠操作的對應的角色類型,也就是說你一出生屬於哪個幫派的已經基本確定了,所以一般都會對角色進行抽象,在工廠抽象層操作的類型肯定也是抽象,“抽象對抽象”---又說了一遍。
基於上面的表述,簡單工廠模式路子很野,你想創建啥我就創建啥,隨便來,這和直線的代碼比起來其實差別不大。工廠方法模式一脈相承,代碼比簡單工廠模式要復雜,但是無形中確規范了不少,依據這樣的模式,代碼分層其實就特別順溜。
好了,對應於工廠模式我剛才說了,你想實現多少就實現多少,這是好處,也是壞處,代碼總歸是有限的,需求泛濫,也總過就人死燈滅的時候,正是由於實現終歸是有限的,所以在實現的時候,如果能不要這么多實現工廠是不是代碼就稍微簡潔點呢。由此,我們就產生了抽象工廠模式,將原先在工廠方法模式中,實現工廠的代碼移到一個統一的抽象層中,再來針對抽象進行實現,看看代碼怎么實現。
創建抽象工廠模式的抽象工廠類AbstractFactory,代碼如下:
1 //抽象工廠模式--抽象工廠 2 public abstract class AbstractFactory { 3 4 public abstract iproduct createPosProdct(); 5 6 public abstract iproduct createMobileProduct(); 7 }
針對抽象類的實現層DefaultFactroy,代碼如下:
1 //抽象工廠模式的工廠實現層 2 public class DefaultFactory extends AbstractFactory{ 3 4 public iproduct createPosProdct() 5 { 6 return new PosProduct(); 7 } 8 9 public iproduct createMobileProduct() 10 { 11 return new MobileProduct(); 12 } 13 }
好,抽象工廠就塑造好了,下面測試,測試代碼如下:
1 public static void main(String[] args) { 2 3 ///---抽象工廠模式 4 AbstractFactory dfactory = new DefaultFactory(); 5 prd = dfactory.createMobileProduct(); 6 System.out.println(prd.getPrdName()); 7 8 prd = dfactory.createPosProdct(); 9 System.out.println(prd.getPrdName()); 10 }
運行結果:
class com.aspnetdream.driver.productImpl.MobileProduct class com.aspnetdream.driver.productImpl.PosProduct
抽象工廠和工廠方法模式我覺得沒有誰好誰壞,不同的應用場景使用不同的模式,在我們現實的工作場景中,處理一個問題,往往是幾種模式一起用,某個應用模式的內部代碼或許有其他的模式來實現。二十四種設計模式,其實每一個割裂開來看,每個都很簡單,上面的代碼相信每一個人都能看的懂,但,如何去用就是基本功的問題,代碼靈活地拓展和應用也同樣是對自身代碼能力的一個要求。
好了,就此擱筆,算是拋磚引玉,歡迎拍磚指教!
我的目錄結構:
最后貼上我的源代碼:http://files.cnblogs.com/aspnetdream/factory.rar