標籤:interface public 現實生活 關鍵點 小汽車
問題提出
Java的原廠模式與現實生活中的工廠的模型是很相似的。工廠是用來做什嗎?當然是用來產生產品。因此在Java的原廠模式的關鍵點就是如何描述好產品和工廠這2個角色之間的關係。
下面來仔細描述一下不同的關係以及對應的設計模式
1)單一產品系,工廠只生產一種類型的產品
650) this.width=650;" src="http://images2015.cnblogs.com/blog/1055141/201704/1055141-20170417224329212-1678195478.png" style="border:none;height:auto;" />
讓我們簡單構思一下簡單的工廠生產模型,既然只有一個產品,那隻需要一個車間就好了,一個車間分別生產三種不同種類的小汽車。好,下面看看簡單工廠的設計模式。
650) this.width=650;" src="http://images2015.cnblogs.com/blog/1055141/201704/1055141-20170417224355899-859322894.png" style="border:none;height:auto;" />
//定義小汽車介面:ICar.javapublic interface ICar {}
public class TopCar implements ICar {}
public class MidCar implements ICar {}
public class LowCar implements ICar {}
650) this.width=650;" src="/img/fz.gif" alt="複製代碼" style="border:none;" />
public class CarSimpleFactory { public static final String TOPTYPE = "toptype"; public static final String MIDTYPE = "midtype"; public static final String LOWTYPE = "lowtype"; private CarSimpleFactory(){ } public static ICar create(String mark){ ICar obj = null; if(mark.equals(TOPTYPE)){ obj = new TopCar(); } else if(mark.equals(MIDTYPE)){ obj = new MidCar(); } else if(mark.equals(LOWTYPE)){ obj = new LowCar(); } return obj; }}
650) this.width=650;" src="/img/fz.gif" alt="複製代碼" style="border:none;" />
簡單工廠功能類編寫步驟:
1.編寫抽象產品介面
2.編寫具體產品子類
3.編寫工廠類。簡單工廠類的特點,它是一個具體的類,非介面型抽象類別。有一個重要的create()方法,並且用if...else或者switch開發建立所需產品。因為可以把這個簡單工廠類實現成一個工具類,所以直接用靜態方法就可以了,如有必要甚至可以把構造方法私人化。
下面考慮一種情形,工廠擴張啦!可以加工生產超級高檔型的汽車。在上面的生產模式下要怎麼修改呢?
1)新增ICar子類SuperCar
2)修改工廠類SimpleCarFactory中的create()方法,添加判斷分支。
子類SuperCar的添加是必然的,然而能不能不用修改工廠類呢?
或者從另一個角度分析,在一個生產線上生產幾種不同種類的產品,這樣我們還需要對每個產品加以判斷種類來分類。當然,假若只有2種種類要區分,這樣當然沒問題,但是若是有多個種類要區分呢?顯然,不能在一條生產線上生產多種種類的產品!那意味著對於每一種種類我們都需要一條生產線。這就是所謂的原廠模式!
650) this.width=650;" src="http://images2015.cnblogs.com/blog/1055141/201704/1055141-20170417224658774-173264373.png" style="border:none;height:auto;" />
public abstract class AbstractFactory { public abstract ICar create();}
650) this.width=650;" id="code_img_closed_fa8cb3de-907c-4613-851e-c050533cd21b" src="/img/jia.gif" style="border:none;" /> View Code
650) this.width=650;" id="code_img_closed_13ea3324-b342-48fb-82c4-ee164edefe08" src="/img/jia.gif" style="border:none;" /> View Code
650) this.width=650;" id="code_img_closed_48ca85fa-0cc4-40af-aa9a-e3cb0aff88f9" src="/img/jia.gif" style="border:none;" /> View Code
而觀察代碼,只要有ICar.java,AbstractFactory.java這兩個檔案,其他具體產品類,工廠類源檔案沒有,編譯也能通過。
對於AbstractFactory,可以定義為抽象類別,也可以定義為介面。這裡的create()是抽象方法,沒參數,表明在具體的子類工廠中建立某個具體產品。
Factory 方法的主要特徵是:當需求分析發生變化是,只需要增加和刪除相應的類,而不是修改已有的類。例如添加超高檔的小汽車,只需要增加SuperCar以及SuperFactory兩個類即可。所以Factory 方法更易於軟體的二次開發以及維護。
當然啦,一個工廠很有可能不止產生一種產品。下面看看多產品系。
2)多產品系,特徵相同
650) this.width=650;" src="http://images2015.cnblogs.com/blog/1055141/201704/1055141-20170417224919259-1811132204.png" style="border:none;height:auto;" />
UML圖與原廠模式基本沒什麼區別,這裡就不再畫了。
一般來說,簡單工廠和原廠模式都是單產品系的,而對於上面這種架構,稱之為抽象工廠。但從本質上來說,抽象工廠和原廠模式是統一的。這裡就不再述說。
3)多產品系,部分特徵相同
650) this.width=650;" src="http://images2015.cnblogs.com/blog/1055141/201704/1055141-20170417225003790-666615638.png" style="border:none;height:auto;" />
public abstract class AbstractFactory { /** * 多產品系,小汽車和公用汽車都有高,中檔類型,小汽車有低檔類型,而公用汽車沒有 */}
public abstract class AbstractFactory1 extends AbstractFactory { public abstract ICar createCar(); //產生小汽車對象 public abstract IBus createBus(); //產生公用汽車對象}
public abstract class AbstractFactory2 extends AbstractFactory { public abstract ICar createCar(); //產生小汽車對象}
這裡著重看看AbstractFactory,AbstractFactory1,AbstractFactory2.
1)具有相同特徵的小汽車和公用汽車放在相同的工廠裡面
2)該類也是抽象類別,表明“特徵是多個”。這裡特徵表示“高中低檔”。
原廠模式大概就講到這裡,看到這裡,相信很多人都有一種,原廠模式原來也不過如此。但是,個人覺得無論什麼設計模式,看上去都似乎很好理解很容易。但是,當遇到問題需要自己分析設計的時候,就頓時沒了頭緒。
原因大概有2個,一是對這種設計模式還並不是十分熟悉和理解,二當然就是沒有實踐過。閑話不多說,下面讓我們操刀實踐一波。
例子:編寫讀檔案功能。讀取文字檔,包括GBK,UTF-8.編碼下的文字檔,要求獲得全文內容;讀取影像檔,包括BMP,GIF,JPG檔案,要求獲得映像寬度,長度,每一點的三基色資訊。
650) this.width=650;" src="http://images2015.cnblogs.com/blog/1055141/201704/1055141-20170417225217634-1489298231.png" style="border:none;height:auto;" />
代碼如下:
讀取文字檔方法需要兩個參數:檔案名稱和編碼方式;而讀取影像檔需要一個參數:檔案名稱。而根據題意,兩種讀取檔案傳回值類型有所差異。
如何用介面屏蔽方法參數個數,傳回值類型的差異,是定義介面的關鍵。
public interface IRead<T> { //如何用介面屏蔽方法參數個數,傳回值類型的差異,這是定義介面的關鍵 T read(String ... in);}
650) this.width=650;" id="code_img_closed_a76a8422-8160-47d3-a900-92106d565f96" src="/img/jia.gif" style="border:none;" /> View Code
650) this.width=650;" id="code_img_closed_c2b4136f-1920-4bc6-a341-4a53bdbb8eba" src="/img/jia.gif" style="border:none;" /> View Code
650) this.width=650;" id="code_img_closed_2e68c5a9-6674-4c58-a738-f29ed525130a" src="/img/jia.gif" style="border:none;" /> View Code
public abstract class AbstractFactory { //定義抽象工廠 public abstract IRead create();}
public class TextFactory extends AbstractFactory { public IRead create(){ return new TextRead(); }}
public class ImageFactory extends AbstractFactory { public IRead create(){ return new ImageRead(); }}
對於上面抽象工廠類其實並不夠完善,如何選擇具體工廠類沒有體現。解決方案有兩種。一是像簡單工廠那樣添加選擇分支。二是使用反射。
下面的代碼是使用了反射技術
650) this.width=650;" src="/img/fz.gif" alt="複製代碼" style="border:none;" />
public abstract class AbstractFactory { public abstract IRead create(); static AbstractFactory create(String className){ AbstractFactory factory = null; try{ Class c = Class.forName(className); factory = (AbstractFactory)c.newInstance(); } catch (Exception ex){ ex.printStackTrace(); } return factory; }}
650) this.width=650;" src="/img/fz.gif" alt="複製代碼" style="border:none;" />
運用反射技術,實現了更加靈活的自動工廠選擇功能。當添加新具體工廠類的時候,不需要修改AbstractFactory類。
Java設計模式:原廠模式