設計模式07—設計模式之Factory 方法模式(Factory Method)(建立型)

來源:互聯網
上載者:User
1.情境問題

匯出資料的應用程式框架

考慮這樣一個實際應用,實現一個匯出資料的應用程式框架,來讓客戶選擇資料的匯出方式(可能有資料庫匯出方式,可能有文本匯出方式),並真正執行資料匯出。

1.1架構的基礎知識1.1.1架構是什嗎?

架構是能完成一定功能的半成品軟體。

1.1.2架構能幹什麼呢?

能完成一定的功能,加快程式開發的速度

給我們一個精良的程式架構

1.1.3對架構的理解

基於架構開發,事情還是那些事情,只是看誰做的問題。

基於架構開發,可以不去做架構所做的事情,但是應該明白架構在幹什麼,以及架構是如何?其功能的。

1.1.4架構與設計模式的關係

                   設計模式比架構更加抽象

                   設計模式是比架構更小的體繫結構元素

                   架構比設計模式更加特例化

1.2問題所在:

         分析上面的應用程式框架,不管使用者選擇什麼樣的匯出格式,最後匯出的都是一個檔案,而且系統不知道究竟要匯出什麼樣的檔案,因此應該有一個介面,來描述最後產生的對象,並操作輸出的檔案。

範例程式碼如下

 

package demo05.factorymethod.example1;/** * 匯出的檔案對象的介面 */public interface ExportFileApi {/** * 匯出內容成為檔案 *  * @param data *            示意:需要儲存的資料 * @return 是否匯出成功 */public boolean export(String data);}

對於實現匯出資料的業務對象的功能,它應該根據需要來建立相應的ExportFileApi的實現對象,因為特定ExportFileApi的實現是與具體的業務相關的,但是對於實現匯出的資料的業務功能對象而言,它並不知道應該建立哪一個ExportFileApi對象,也不知道如何建立

2.解決問題      2.1使用Factory 方法模式來解決問題

Factory 方法模式定義:定義一個用於建立對象的介面,讓子類決定執行個體化哪個類,Factory Method使一個類的執行個體化延遲到其子類。

                   Factory 方法模式的解決思路很有意思,那就是不解決,採取無為而治的方式。

                   Factory 方法模式的結構

Product實際使用對象的介面

ConcreteProduct具體的介面的實現對象

Creator建立器,聲明Factory 方法

ConcreteCreator具體的建立器的對象,覆蓋實現Creator定義的Factory 方法,返回具體的Product執行個體

      2.2Factory 方法模式範例程式碼

 

package demo05.factorymethod.example2;/** * Factory 方法所建立的對象的介面 */public interface Product {// 可以定義Product的方法}

package demo05.factorymethod.example2;/** * 具體的Product對象 */public class ConcreteProduct implements Product {// 實現Product要求的方法}

package demo05.factorymethod.example2;/** * 建立器,聲明Factory 方法 */public abstract class Creator {/** * 建立Product的Factory 方法 *  * @return Product對象 */protected abstract Product factoryMethod();/** * 示意方法,實現某些功能的方法 */public void someOperation() {// 通常在這些方法實現中,需要調用Factory 方法來擷取Product對象Product product = factoryMethod();}}

package demo05.factorymethod.example2;/** * 具體的建立器實現對象 */public class ConcreteCreator extends Creator {public Product factoryMethod() {// 重定義Factory 方法,返回一個具體的Product對象return new ConcreteProduct();}}
      2.3使用Factory 方法模式解決情境中出現的問題,首先要匹配哪些是Product哪些是Creator

                   使用Factory 方法模式實現樣本程式結構


         代碼實現如下:

 

package demo05.factorymethod.example3;/** * 匯出的檔案對象的介面 */public interface ExportFileApi {/** * 匯出內容成為檔案 *  * @param data *            示意:需要儲存的資料 * @return 是否匯出成功 */public boolean export(String data);}
package demo05.factorymethod.example3;/** * 匯出成文字檔格式的對象 */public class ExportTxtFile implements ExportFileApi {public boolean export(String data) {// 簡單示意一下,這裡需要操作檔案System.out.println("匯出資料" + data + "到文字檔");return true;}}

package demo05.factorymethod.example3;/** * 匯出成Database Backup檔案形式的對象 */public class ExportDB implements ExportFileApi {public boolean export(String data) {// 簡單示意一下,這裡需要操作資料庫和檔案System.out.println("匯出資料" + data + "到Database Backup檔案");return true;}}

package demo05.factorymethod.example3;/** * 實現匯出資料的業務功能對象 */public abstract class ExportOperate {/** * 匯出檔案 *  * @param data *            需要儲存的資料 * @return 是否成功匯出檔案 */public boolean export(String data) {// 使用Factory 方法ExportFileApi api = factoryMethod();return api.export(data);}/** * Factory 方法,建立匯出的檔案對象的介面對象 *  * @return 匯出的檔案對象的介面對象 */protected abstract ExportFileApi factoryMethod();}

package demo05.factorymethod.example3;/** * 具體的建立器實現對象,實現建立匯出成文字檔格式的對象 */public class ExportTxtFileOperate extends ExportOperate {protected ExportFileApi factoryMethod() {// 建立匯出成文字檔格式的對象return new ExportTxtFile();}}

package demo05.factorymethod.example3;public class Client {public static void main(String[] args) {// 建立需要使用的Creator對象ExportOperate operate = new ExportDBOperate();// 調用輸出資料的功能方法operate.export("測試資料");}}

3.模式講解3.1Factory 方法模式的功能

         Factory 方法模式的主要功能是讓父類在不知道具體實現的情況下,完成自身功能的調用,而具體的實現延遲到子類來實現。

3.2實現成抽象類別

         Factory 方法的實現中,通常父類會是一個抽象類別,裡麵包含所需建立對象的抽象方法,這些抽象方法就是Factory 方法。

         這裡要注意一個問題,子類在實現這些抽象方法的時候,通常並不是真正的由子類來實現具體的功能,而是在子類的方法裡面做選擇,選擇具體的產品實現對象。

3.3實現成具體的類

         也可以把父類實現成一個具體的類。通常這種情況還需要具體的子類來決定具體要如何建立父類所需要的對象。也把這種情況,成為Factory 方法為子類提供了掛鈎。通過Factory 方法,可以讓子類對象來覆蓋父類的實現,從而提供更好的靈活性。

3.4Factory 方法的參數和返回

一般返回的是被建立對象的介面對象,當然可以是抽象類別或者是一個具體類的執行個體。

3.5誰來使用Factory 方法建立的對象

         在原廠模式方法裡面,是Creator中的其他方法在使用     Factory 方法建立的對象,但是Factory 方法一般不提供給Creator外部使用。

3.5.1用戶端使用Creator對象的情況

 

package demo05.factorymethod.example4;/** * 用戶端使用Creator對象的情況下,Creator的基本實現結構 */public abstract class Creator {/** * Factory 方法,一般不對外 *  * @return 建立的產品對象 */protected abstract Product factoryMethod();/** * 提供給外部使用的方法, 用戶端一般使用Creator提供的這些方法來完成所需要的功能 */public void someOperation() {// 在這裡使用Factory 方法Product p = factoryMethod();}}

3.5.2用戶端使用Creator創造出來的對象

 

package demo05.factorymethod.example5;/** * 用戶端使用Creator來建立用戶端需要的對象的情況下,Creator的基本實現結構 */public abstract class Creator {/** * Factory 方法,一般不對外,建立一個組件對象 *  * @return 建立的產品對象,一般是另一個產品對象的組件 */protected abstract Product1 factoryMethod1();/** * Factory 方法,一般不對外,建立一個組件對象 *  * @return 建立的產品對象,一般是另一個產品對象的組件 */protected abstract Product2 factoryMethod2();/** * 建立用戶端需要的對象,用戶端主要使用產品對象來完成所需要的功能 *  * @return 用戶端需要的對象 */public Product createProduct() {// 在這裡使用Factory 方法,得到用戶端所需對象的組件對象Product1 p1 = factoryMethod1();Product2 p2 = factoryMethod2();// Factory 方法建立的對象是建立用戶端對象所需要的Product p = new ConcreteProduct();p.setProduct1(p1);p.setProduct2(p2);return p;}}

3.6Factory 方法模式的調用順序如下3.6.1使用Creator對象調用的如下

 

 

3.6.2使用Creator建立出來的對象的調用情況如下

 

4.Factory 方法模式與IoC/DI

IoC控制反轉

DI依賴注入

      4.1理解概念              4.1.1參與者都有誰?

              一個是某個對象,一個是IoC/DI容器,有一個是某個對象的外部資源

              這裡某個對相關當然是指任意的某個Java對象

              4.1.2誰依賴誰?

              當然是某個對象依賴IoC/DI容器

              4.1.3為什麼需要依賴?

              對象需要IoC/DI的容器來提供對象需要的外部資源。

              4.1.4誰注入誰?

              很明顯是IoC/DI的容器來注入某個對象

              4.1.5到底注入什嗎?
              注入某個對象所需要的外部資源

              4.1.6誰控制誰?
              當然是IoC/DI的容器來控制對象

              4.1.7控制什嗎?

              主要是控制對象執行個體的建立

              4.1.8為啥叫做“反轉”?
              如果在A中需要C,那麼會直接建立C的對象,這樣就是A主動擷取所需要的資源檔C類,這樣被稱為是正向的。那麼什麼叫做反向呢?就是說A不再主動擷取C類。而是被動等待,等待IoC/DI擷取一個C類的執行個體,然後反向的注入A中。

              4.1.9依賴注入和控制反轉是同一概念嗎?

              依賴注入:應用程式依賴容器建立,並注入它所需要的外部資源;

              控制反轉:容器控制應用程式,由容器反向的嚮應用程式注入其所需要的外部資源。

4.2Factory 方法模式與IoC/DI的關係

     上面講了,有了IoC/DI後,應用程式不再主動了,而是被動的等待由容器來注入資源。那麼在編寫代碼的時候,一旦要用到外部資源,就會開一個視窗,讓容器能注入進來,也就是提供給容器使用過的注入的途徑,當然這都不是重點,我們用setter注入來樣本一下,使用IoC/DI的範例程式碼如下:

 

 

package demo05.factorymethod.example6;public class A {/** * 等待被注入進來 */private C c = null;/** * 注入資源C的方法 *  * @param c *            被注入的資源 */public void setC(C c) {this.c = c;}public void t1() {// 這裡需要使用C類,可是又不讓主動去建立C了,怎麼辦?// 反正就要求從外部注入,這樣更省心,// 自己不用管怎麼擷取C,直接使用就好了c.tc();}}

package demo05.factorymethod.example6;public interface C {public void tc();}

Factory 方法模式實現上述功能,範例程式碼如下

 

package demo05.factorymethod.example6;public abstract class A1 {/** * Factory 方法,建立C1,類似於從子類注入進來的途徑 *  * @return C1的對象執行個體 */protected abstract C1 createC1();public void t1() {// 這裡需要使用C1類,可是不知道究竟是用哪一個,也就不主動去建立C1了,怎麼辦?// 反正會在子類裡面實現,這樣更省心,這裡不用管怎麼擷取C1,直接使用就好了createC1().tc();}}
package demo05.factorymethod.example6;public class A2 extends A1 {protected C1 createC1() {// 真正的選擇具體實現,並建立對象return new C2();}}

package demo05.factorymethod.example6;public interface C1 {public void tc();}

package demo05.factorymethod.example6;public class C2 implements C1 {public void tc() {// TODO Auto-generated method stub}}

5平衡的類階層      5.1平衡的類階層的含義:

         假如有兩個類階層,其中一個類層次中的每個類在另一個類層中都有一個對應的類的結構,就被稱為平行的類階層。

         範例如下:舉一個硬碟的例子

        

台式機希捷硬碟對象對應著台式機希捷硬碟對象的行為,筆記本IBM硬碟對應著筆記本IBM硬碟的行為,這是一種典型的平行的類階層。

主要用來把一個類層次中的某些行為分離出來,讓類層次中的類把原本屬於自己的原則,委託給分離出去的類去實現,從而使類層次更加簡單,因此被稱為平行的類階層。

6.參數化Factory 方法

         定義:通過Factory 方法傳遞參數,根據參數的不同,來建立不同的產品對象。

情境問題範例程式碼如下

 

package demo05.factorymethod.example7;/** * 實現匯出資料的業務功能對象 */public class ExportOperate {//不再是抽象類別了/** * 匯出檔案 *  * @param type *            使用者選擇的匯出類型 * @param data *            需要儲存的資料 * @return 是否成功匯出檔案 */public boolean export(int type, String data) {// 使用Factory 方法ExportFileApi api = factoryMethod(type);return api.export(data);}/** * Factory 方法,建立匯出的檔案對象的介面對象 *  * @param type *            使用者選擇的匯出類型 * @return 匯出的檔案對象的介面對象 */protected ExportFileApi factoryMethod(int type) {ExportFileApi api = null;// 根據類型來選擇究竟要建立哪一種匯出檔案對象if (type == 1) {api = new ExportTxtFile();} else if (type == 2) {api = new ExportDB();}return api;}}

那麼用戶端這樣,如下:

 

package demo05.factorymethod.example7;public class Client {public static void main(String[] args) {// 建立需要使用的Creator對象ExportOperate operate = new ExportOperate();// 下面變換傳入的參數來測試參數化Factory 方法operate.export(1, "Test1");}}

從此以後擴充參數化Factory 方法會變得非常容易:如下

 

package demo05.factorymethod.example7;/** * 擴充ExportOperate對象,加入可以匯出XML檔案 */public class ExportOperate2 extends ExportOperate {/** * 覆蓋父類的Factory 方法,建立匯出的檔案對象的介面對象 *  * @param type *            使用者選擇的匯出類型 * @return 匯出的檔案對象的介面對象 */protected ExportFileApi factoryMethod(int type) {ExportFileApi api = null;// 可以全部覆蓋,也可以選擇自己感興趣的覆蓋,// 這裡只想添加自己新的實現,其他的不管if (type == 3) {api = new ExportXml();} else {// 其他的還是讓父類來實現api = super.factoryMethod(type);}return api;}}

用戶端實現也很容易,代碼如下:

package demo05.factorymethod.example7;public class Client {public static void main(String[] args) {// 建立需要使用的Creator對象ExportOperate operate = new ExportOperate2();// 下面變換傳入的參數來測試參數化Factory 方法operate.export(1, "Test1");operate.export(2, "Test2");operate.export(3, "Test3");}}

 7.Factory 方法模式的優缺點:

         優點:可以在不知道具體實現的情況下編程。

                            更容易擴充新對象的版本

                            串連平行的類層次

         缺點:具體產品對象和Factory 方法的耦合性

8.思考Factory 方法模式:

         本質:延遲到子類才實現。

注意:在選擇實現的時候,可能會感覺像是簡單原廠模式,實際上具體實現都是“選擇實現”,但是不同點在於簡單工廠是在工廠中實現,而Factory 方法中會把這個工作延遲到子類來實現。

9.對設計原則的體現

         Factory 方法模式很好的體現了“依賴倒置原則”

         依賴倒置原則告訴我們:要依賴抽象,不要依賴具體類。

10.心得

         泥馬,這個Factory 方法模式真蛋疼,我理解了好幾天呢,說實話,不好理解,現在我只處於看懂了的階段,還沒有融會貫通,先寫出來,以後慢慢理解

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.