設計模式之原廠模式(Factory Pattern)

來源:互聯網
上載者:User

標籤: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)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.