天天看點

設計模式:(1)工廠方法模式(Factory Method)

設計模式:(1)工廠方法模式(Factory Method)

介紹第一個設計模式前,我想給大家分享一下關于設計模式的分類。

“每一個設計模式描述了在我們周圍不斷重複發生的問題,以及該問題的解決方案的核心。這樣,你就能一次又一次地使用該方案而不必做重複的勞動”。這就是使用設計模式的意義。設計模式的核心在于提供了一類問題的解決方案和總結的精化,使得人們可以簡單友善的使用成功的設計和體系結構。

設計模式一般有4個要素:

模式名稱(pattern name)。一個助記符号,他用一兩個詞描述模式的問題、解決方案和效果。

問題(problem)。問題描述了應該在何時使用設計模式。

解決方案(solution)。解決方案描述了設計的組成成分,他們之間的互相關系及各自的職責和協作方式。

效果(consequences)。效果描述了使用設計模式的效果及使用設計模式權衡的問題。盡管效果并不是設計模式要素的關鍵,但是用效果來評價設計模式的使用代價和好處至關重要。效果包括系統的靈活性、擴充性和可移植性。

按照設計模式的使用目的可将其分為三大類,如下圖所示:

設計模式:(1)工廠方法模式(Factory Method)

建立型模式與對象的建立有關,結構型模式處理類和對象的組合,行為模式對類或對象怎樣互動怎樣配置設定職責進行描述。

建立型模式(Creational Pattern)抽象了執行個體化過程,它們幫助一個系統獨立于如何建立、組合和表示它的那些對象。建立型模式分為類的建立模式和對象的建立模式兩種:

類的建立模式:類的建立模式使用繼承關系,把類的建立延遲到子類,進而封裝了用戶端将得到哪些具體類的資訊,并且隐藏了這些類的執行個體是如何被建立和放在一起的。

對象的建立模式:對象的建立模式把對象的建立過程動态地委派給另一個對象,進而動态地決定用戶端将得到哪些具體類的執行個體。

設計模式的實作其實就是解決六大設計模式基本原則中提出的問題,在閱讀下面分享的内容的時候如果有人對設計模式的六大基本原則比較陌生可以翻看公衆号的曆史進行檢視。如果對設計模式的六大基本原則已經很熟悉的朋友請留意我在分享的第一個設計模式中所涉及的設計原則。

第一個設計模式:工廠方法(Factory Method)

意圖:定義一個用于建立對象的抽象類Factory,讓具體的ConcreteFactory子類決定執行個體化哪一個IProduct類型的産品,該模式使得一個類(即IProduct)的執行個體化延遲到其子類(即Product)。

類型:類建立型模式

結構UML圖:

設計模式:(1)工廠方法模式(Factory Method)

其中:

  • IProduct 定義工廠方法所建立的對象的接口(抽象類或者接口)。
  • Product 定義具體實作的産品。
  • Factory 抽象工廠類用于規範化所有建立具體産品的工廠類的行為,其中聲明一個建立産品的方法,該方法傳回一個IProduct類型的對象。Factory 也可以定義一個預設的工廠方法,它傳回一個預設的具體Product對象。
  • ConcreteFactory 重定義工廠方法以傳回一個具體的Product對象。

模式标準代碼:

interface IProduct {

       public void productMethod();

}

 

class Product implements IProduct {

       public void productMethod() {

              System.out.println("具體産品");

       }

}

 

abstract class Factory {
       public abstract IProduct  createProduct();
       public void anOperation(){
         System.out.println("預設做一點兒事情吧!");
       }
  }

 

class ConcreteFactory extends Factory {
       public IProduct  createProduct() {
        return new Product();
       }
  }

 

public class Client {

       public static void  main(String[] args) {

              Factory factory = new  Factory();

              IProduct product =  factory.createProduct();

              product.productMethod();

       }

}

           

通過分析工廠方法的類圖和示例代碼可以得出:

首先通過工廠方法模式實作了對複雜對象的生成過程的隐蔽,這樣使調用者隻關心生成的對象而不必關心具體的對象的生成過程。是以可以在任何需要生成複雜對象的地方,使用工廠方法模式。有一點需要注意的地方就是複雜對象适合使用工廠方法模式,而簡單對象,特别是隻需要通過new就可以完成建立的對象,無需使用工廠方法模式。如果使用工廠方法模式,就需要引入一個工廠類,會增加系統的複雜度。

其次,工廠模式是一種典型的解耦模式,迪米特法則在工廠模式中表現的尤為明顯。假如調用者自己組裝産品需要增加依賴關系時,可以考慮使用工廠模式。将會大大降低對象之間的耦合度。

再次,由于工廠模式是依靠抽象架構的,它把執行個體化産品的任務交由實作類完成,擴充性比較好即遵循了“開閉原則”,也就是說,當需要系統有比較好的擴充性時,可以考慮工廠方法模式,不同的産品用不同的實作工廠來組裝。

工廠方法模式是簡單工廠模式(該模式比較簡單不做介紹)的衍生,解決了許多簡單工廠模式的問題。

此外需要提及的是,上面的總結同樣适用于簡單工廠模式和抽象工廠模式,抽象工廠模式将會在未來的分享中提及。

應用場景例子:

下面我們就以生産泡面的過程為例子說明工廠方發模式的優點。生産泡面的過程主要分為:生産面條,生産調料,生産包裝盒和生産餐具等部分。如果不用工廠方法模式:

class Noodles {

   public void getNoodles() {

      System.out.println("生産面條!");

   }

}




class Seasoning {

   public void getSeasoning() {

      System.out.println("生産調料!");

   }

}




class Box {

   public void getBox() {

      System.out.println("生産包裝盒!");

   }

}




class Tableware {

   public void getTableware() {

      System.out.println("生産餐具!");

   }

}




interface IInstantNoodles {

   public void showInstantNoodles();

}




class InstantNoodles implements IInstantNoodles {

   private Noodles noodles;

   private Seasoning seasoning;

   private Box box;

   private Tableware tableware;

   public InstantNoodles(Noodles noodles, 

        Seasoning  seasoning, Box box,

        Tableware  tableware) {

      this.noodles = noodles;

      this.seasoning = seasoning;

      this.box = box;

      this.tableware = tableware;

   }

   public void showInstantNoodles() {

      noodles.getNoodles();

      seasoning.getSeasoning();

      box.getBox();

      tableware.getTableware();

   }

}




public class Client {

   public static void  main(String[] args) {

      Noodles  noodles = new Noodles();

      Seasoning  seasoning = new Seasoning();

      Box  box = new Box();

      Tableware  tableware = new Tableware();

      IInstantNoodles  instantNoodles = 

           new InstantNoodles(noodles, 

                 seasoning,box,  tableware);

      instantNoodles.showInstantNoodles();

   }

}

           

可以看到,調用者為了擷取泡面還需要另外執行個體化面條、調料,包裝盒和餐具而這些友善面的的組成成分與調用者無關的,嚴重違反了迪米特法則,耦合度太高。并且非常不利于擴充。另外,本例中友善面的組成成分還是比較具體的,在實際應用中,可能這些産品的組成成分也都是抽象的,調用者根本不知道怎樣組裝産品。假如使用工廠方法的話,整個架構就顯得清晰了許多。

/**注意:泡面的組成成分類和上面的代碼中的類相同,泡面接口和其實作類也相同**/

abstract class  InstantNoodlesFactory {

   public abstract IInstantNoodles productInstantNoodles();

}

 

class InstantNoodlesConcreteFactory extends InstantNoodlesFactory {

   @Override

   public IInstantNoodles productInstantNoodles() {

      Noodles  noodles = new Noodles();

      Seasoning  seasoning = new Seasoning();

      Box  box = new Box();

      Tableware  tableware = new Tableware();

      IInstantNoodles  instantNoodles 

        =  new  InstantNoodles(noodles, seasoning,

                      box, tableware);

      return instantNoodles;

   }

}

 

publicclass Client {

   public static void  main(String[] args) {

      InstantNoodlesFactory  instantNoodleFactory 

                = new  InstantNoodlesConcreteFactory();

      IInstantNoodles  instantNoodles 

                = instantNoodleFactory.productInstantNoodles();

      instantNoodles.showInstantNoodles();

   }

}

           

使用工廠方法後,調用端的耦合度大大降低了。并且對于工廠來說,是可以擴充的,以後如果想組裝其他的泡面,隻需要再增加一個工廠類的實作就可以。無論是靈活性還是穩定性都得到了極大的提高。

---------------

這個模式也就寫到這裡了,我的了解就是這樣。并且我感覺有些餓了,還好有工廠方法模式生産泡面,這就避免了我去動手了。再啰嗦一句,喜歡我的分享的朋友記得關注我的公衆号。可搜尋  程式員日記,或者搜尋 code2note關注,也可簡單的點選文章開始的公衆号名稱關注。

閱讀 投訴

繼續閱讀