標籤:des style blog color os 使用 java strong div
一.什麼是原廠模式?
1.“簡單原廠模式”,Simple Factory Pattern
也就是常用的在Factory類中定義靜態方法負責new對象的方式。
摘要中提到過“嚴格地說,這種被稱為“簡單原廠模式”的方式根本不能稱之為“模式””,雖然靜態Factory 方法並不是真正的“設計模式”,但這種方式的應用也很廣泛,也能帶來一些好處,所以我們不能因為它不是“設計模式”就拋棄它。
2.Factory 方法模式,Factory Method Pattern
是原廠模式的核心
定義一個抽象的“Factory 方法”來負責new對象,由該類的擴充類來實現如何new的過程
這種方式成功分離了對象建立過程與對象行為(暫不做解釋),確切地說是把對象建立“下放”到了子類。(注意這裡的動詞——“下放”)
3.抽象原廠模式,Abstract Factory Pattern
是對Factory 方法模式的一種應用與擴充
把多個“Factory 方法”封裝在一個抽象工廠類中,以實現“new一組對象”的目的
二.一般方式(不用原廠模式)
我們來開一個小店賣衣服,首先需要ColthesStore類負責接收訂單返回做好的衣服,ClothesStore類需要依賴Clothes類,畢竟要操作的具體對象是Clothes,ClothesStore中還要有做衣服的工序(製作、加工裝飾。。)
那麼我們的ClothesStore將是這樣的:
package FactoryPattern;/** * @author ayqy * 不使用原廠模式,直接建立具體對象 * */public class ClothesStore {String type;//定義衣服類型Clothes clothes;//衣服對象/** * @author ayqy * 定義內部類Clothes * */class Clothes{String type;//類型String desc;//描述String cloth;//布料public Clothes(String type, String desc, String cloth){this.type = type;this.desc = desc;this.cloth = cloth;}public String toString(){return type+ "," + desc + "," + cloth;}}public ClothesStore(String type){this.type = type;}/** * @return 返回未經裝飾加工的衣服 */private Clothes createClothes(String type){if(type.equals("外套")){return new Clothes("外套", "一件好看的外套", "麻布");}else if(type.equals("內衣")){return new Clothes("內衣", "一件舒適的內衣", "棉布");}elsereturn null;}/** * @return 返回做好的衣服 */public Clothes getClothes(){clothes = createClothes(type);decorate(clothes);//對衣服進行裝飾return clothes;}private void decorate(Clothes clothes){//給衣服添加裝飾(圖案、紋樣等等)System.out.println("精心裝飾完畢,衣服變得更漂亮了");}}
P.S.代碼中把Clothes定義為內部類,只是為了節省篇幅簡化結構,效果一樣
我們發現ClothesStore對Clothes有著很強的依賴(過分依賴“具體”可不是一件好事兒。。),一旦Clothes發生變化(如有了新的成員變數與成員函數),我們的ClothesStore可能就不得不跟著修改了,尤其是負責new衣服對象的部分:
/*** @return 返回未經裝飾加工的衣服*/private Clothes createClothes(String type){if(type.equals("外套")){return new Clothes("外套", "一件好看的外套", "麻布");}else if(type.equals("內衣")){return new Clothes("內衣", "一件舒適的內衣", "棉布");}elsereturn null;}
一旦有了新的type我們就要添加一個else if來應對變化
而且由於ClothesStore與具體的Clothes類綁定在一起,導致ClothesStore不易於擴充,很難複用
三.“簡單原廠模式”
把createClothes方法移動到ClothesFactory中作為一個靜態Factory 方法,就像這樣:
package FactoryPattern.SimpleFactoryPattern;/** * @author ayqy * 定義靜態Factory 方法 * */public class ClothesFactory {/** * @return 返回未經裝飾加工的衣服 */public static Clothes createClothes(String type){if(type.equals("外套")){return new Clothes("外套", "一件好看的外套", "麻布");}else if(type.equals("內衣")){return new Clothes("內衣", "一件舒適的內衣", "棉布");}elsereturn null;}}
P.S.這次必須把Clothes拿出來作為一個獨立的類了(內部類無法訪問),除此之外,ClothesStore中的getClothes方法也要做相應改變。。不要在意這些細節
應用簡單原廠模式之後,我們確實把new對象的部分獨立出來了,這樣做的好處是:
當Clothes發生變化時,我們可以在ClothesFactory中直接修改create方法,而不是在ClothesStore的長篇代碼中尋找Create部分
而且與之前的“一般方式”對比,代碼幾乎沒有發生什麼變化,很容易把之前的代碼改成應用簡單原廠模式之後的代碼,所以很多開發人員喜歡這種方式
-------
“簡單原廠模式”並不是真正的原廠模式,它的優勢也是極其有限的,不過沒關係,我們還有Factory 方法模式,這次是貨真價實的原廠模式
四.Factory 方法模式
定義抽象的“Factory 方法”,負責具體實現,全新的ClothesStore將是這樣的:
package FactoryPattern.FactoryMethodPattern;/** * @author ayqy * 使用Factory 方法模式,定義抽象的Factory 方法來new產品 * */public abstract class ClothesStore {String type;//定義衣服類型Clothes clothes;//衣服對象public ClothesStore(String type){this.type = type;}//定義Factory 方法,由擴充類來實現具體製作細節public abstract Clothes createClothes(String type);/** * @return 返回做好的衣服 */public Clothes getClothes(){clothes = createClothes(type);decorate(clothes);//對衣服進行裝飾return clothes;}private void decorate(Clothes clothes){//給衣服添加裝飾(圖案、紋樣等等)System.out.println("精心裝飾完畢,衣服變得更漂亮了");}}
我們發現ClothesStore變成Abstract的了,裡面封裝了衣服的製作工序以及實現細節,但並沒有實現Create過程
下一步是要擴充ClothesStore類,實現具體Create細節,就像這樣:
package FactoryPattern.FactoryMethodPattern;/** * @author ayqy * 擴充ClothesStore,實現具體製作細節 * */public class DefaultClothesStore extends ClothesStore{public DefaultClothesStore(String type) {super(type);}/* * 實現具體製作細節 */@Overridepublic Clothes createClothes(String type) {if(type.equals("外套")){return new Clothes("外套", "一件好看的外套", "麻布");}else if(type.equals("內衣")){return new Clothes("內衣", "一件舒適的內衣", "棉布");}elsereturn null;}}
嗯,現在我們已經成功應用Factory 方法模式了,讓我們來看看相比之前的簡單原廠模式,這個貨真價實的原廠模式有哪些特點
1.同樣實現了new對象的具體過程與對象行為的分離,但不同的是我們是利用繼承(擴充)來實現的,也就是開篇提到的“下放”(把具體實現放到更低的類層次上)
2.每一個具體Store都必須實現自己的Create細節,但同時又可以利用基類Store的製作工藝(decorate方法等等)
3.一個抽象的Factory 方法輕鬆實現了原廠模式(甚至Factory自始至終根本沒有出現,但我們確實已經實現了“工廠”,不是嗎?)
五.抽象原廠模式
抽象原廠模式是對上一種方式的擴充,在上面我們只能Create一個產品,但很多時候我們需要Create一組產品,比如衣服的原料,包括布料、染料、線、紐扣等等,這時候就需要應用抽象原廠模式來實現:
package FactoryPattern.AbstractFactoryPattern;/** * @author ayqy * 定義原料工廠 * */public abstract class ResourcesFactory {public abstract Cloth getCloth();//擷取布料public abstract Color getColor();//擷取染料public abstract Button getButton();//擷取紐扣//需要的其它Factory 方法}
抽象工廠中的類型都是自訂介面,例如:
package FactoryPattern.AbstractFactoryPattern;/** * @author ayqy * 定義Cloth介面 */public interface Cloth {//屬性//行為}
有了原料工廠,那麼ClothesStore也要做相應的改變來適應這種新的結構:
package FactoryPattern.AbstractFactoryPattern;/** * @author ayqy * 擴充ClothesStore,實現具體製作細節 * */public class DefaultClothesStore extends ClothesStore{public DefaultClothesStore(String type, ResourcesFactory res) {super(type, res);}/* * 實現具體製作細節 */@Overridepublic Clothes createClothes(String type) {if(type.equals("外套")){//擷取所需原料Cloth cloth = res.getCloth();Color color = res.getColor();Button button = res.getButton();//製作衣服return new Clothes("外套", color.toString() + button.toString(), cloth.toString());}else if(type.equals("內衣")){//擷取所需原料Cloth cloth = res.getCloth();Color color = res.getColor();Button button = res.getButton();//製作衣服return new Clothes("內衣", color.toString() + button.toString(), cloth.toString());}elsereturn null;}}
現在建立Store對象時需要一個具體ResourcesFactory參數(具體的原料工廠實現了所有的getXXXFactory 方法),具體的Store只負責具體製作過程,需要什麼原料都可以從ResourceFactory中取得,具體Store做衣服後,由Store基類負責工藝加工(decorate方法等等),最後由具體的Store返回精加工完畢的衣服
整個結構很疏鬆,低耦合,易擴充
-------
除此之外,還有必要提及一個OO設計原則——“依賴倒置原則”
通過觀察類結構我們可以發現:
高層組件Store依賴Clothes,同時低層組件ResourcesFactory也依賴Clothes(這就是“依賴倒置”,即低層組件反過來依賴高層組件,同時高低層組件都依賴抽象)
這樣的設計有著極易擴充的優勢(抽象意味著可擴充。。)
五.總結
其實開篇第一部分就是總結,這裡要強調的是:事物都有兩面性,一個好的東西必然存在缺點,設計模式也不例外。
抽象原廠模式看起來真的不錯,但是也存在致命的缺點:多級抽象引起的結構複雜化問題
設計模式之原廠模式(Factory Pattern)