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