我眼中的所謂工廠模式


  說起軟件架構中的設計模式,大多數人肯定第一句就是,工廠模式。准確講經典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

   


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM