設計模式解密(2)- 工廠模式(簡單工廠、工廠方法、抽象工廠)


1、前言

工廠模式主要是為創建對象提供接口,將創建對象的過程隔離起來,實現了創建者與調用者的分離,提高了程序的靈活性;

核心本質:
  實例化對象,用工廠方法代替new操作;
  將選擇實現類、創建對象統一管理和控制,從而將調用者跟我們實現類解耦;

工廠模式分類:
  簡單工廠模式(Simple Factory)(又稱:靜態工廠方法模式)
  工廠方法模式(Factory Method)
  抽象工廠模式(Abstract Factory)

GOF在《設計模式》一書中將工廠模式分為兩類:工廠方法模式(Factory Method)與抽象工廠模式(Abstract Factory),將簡單工廠模式(Simple Factory)看為工廠方法模式的一種特例,兩者歸為一類;

 類型:創建型模式

2、簡單工廠模式

2-1、介紹

  簡單工廠模式又被稱為靜態工廠方法模式;

  簡單工廠模式是由一個工廠(注意是一個!)對象決定創建出哪一種產品類的實例;

  實現方式的實質:由一個工廠類根據傳入的參數,動態決定應該創建哪一個產品類(這些產品類繼承自一個父類或接口)的實例;

  現實生活中,工廠是負責生產產品的;同樣在設計模式中,簡單工廠模式我們可以理解為負責生產對象的一個類,稱為“工廠類”;

     英文:Simple Factory

 

2-2、解決的問題

將“類實例化的操作”與“使用對象的操作”分開,讓使用者不用知道具體參數就可以實例化出所需要的“產品”類,從而避免了在客戶端代碼中顯式指定,實現了解耦;
即使用者可直接消費產品而不需要知道其生產的細節;

 

2-3、實例引入

背景:這有一個手機生產工廠,能生產多種手機

先定義一個抽象手機類:

package com.designmode.factory.simple;
/**
* 類說明 :抽象手機類
*/
public abstract class Mobile {

}

定義具體的手機:小米手機

package com.designmode.factory.simple;
/**
* 類說明 :具體手機--小米手機
*/
public class XiaomiMobile extends Mobile{

}

定義具體的手機:華為手機

package com.designmode.factory.simple;
/**
* 類說明 :具體手機--華為手機
*/
public class HuaweiMobile extends Mobile{

}

最后定義一個工廠:

package com.designmode.factory.simple;
/**
* 類說明 :
*/
public class MobileFactory {
	/**
	 * 靜態工廠方法
	 * @param mobiletype
	 * @return
	 */
	public static Mobile product(String mobiletype){
		Mobile mobile = null;  
        if ("xiaomi".equals(mobiletype)) {  
        	mobile = new XiaomiMobile();  
            System.out.println("生產小米手機.");  
        } else if ("huawei".equals(mobiletype)) {  
        	mobile = new HuaweiMobile();  
            System.out.println("生產華為手機.");  
        } else {  
            System.out.println("不能生產該手機類型.");  
        }  
        return mobile;  
	}
}

下面咱們來生產手機:

package com.designmode.factory.simple;

/**
* 類說明 :測試
*/
public class Test {
	public static void main(String[] args) {
		/**
		 * 客戶要訂購生產小米手機
		 */
		MobileFactory.product("xiaomi");
		/**
		 * 客戶要訂購生產華為手機
		 */
		MobileFactory.product("huawei");
		/**
		 * 客戶要訂購生產錘子手機
		 */
		MobileFactory.product("chuizi");
	}
}

結果:

生產小米手機.
生產華為手機.
不能生產該手機類型.

 

2-4、優缺點

優點:
  將創建實例的工作與使用實例的工作分開,使用者不必關心類對象如何創建,只需要傳入工廠需要的參數即可;

  把初始化實例時的工作放到工廠里進行,使代碼更容易維護;

  更符合面向對象的原則 & 面向接口編程;

 缺點:
  工廠類集中了所有實例(產品)的創建邏輯,一旦這個工廠不能正常工作,整個系統都會受到影響;

  違背“開放 - 關閉原則”,一旦添加新產品就不得不修改工廠類的邏輯,這樣就會造成工廠邏輯過於復雜,對於系統維護和擴展不夠友好;

  簡單工廠模式由於使用了靜態工廠方法,靜態方法不能被繼承和重寫,會造成工廠角色無法形成基於繼承的等級結構;

 

2-5、應用場景

  (1) 工廠類負責創建的對象比較少,由於創建的對象較少,不會造成工廠方法中的業務邏輯太過復雜

  (2) 客戶端只知道傳入工廠類的參數,對於如何創建對象並不關心

  (3) 鑒於該模式的缺點,因此一般只在很簡單的情況下應用該模式

3、工廠方法模式

3-1、介紹

  工廠方法模式,又稱工廠模式、多態工廠模式和虛擬構造器模式,通過定義工廠父類負責定義創建對象的公共接口,而子類則負責生成具體的對象;

  抽象工廠是工廠方法模式的核心,所有創建對象的工廠類都必須實現該接口;

  英文:Factory Method

     定義:定義一個用於創建對象的接口,讓子類決定實例化哪一個類,Factory Method使一個類的實例化延遲到了子類;

 

3-2、解決的問題

  工廠一旦需要生產新產品就需要修改工廠類的方法邏輯,違背了“開放 - 關閉原則“

  即簡單工廠模式的缺點

  之所以可以解決簡單工廠的問題,是因為工廠方法模式把具體產品的創建推遲到工廠類的子類(具體工廠)中,此時工廠類不再負責所有產品的創建,而只是給出具體工廠必須實現的接口,這樣工廠方法模式在添加新產品的時候就不修改工廠類邏輯而是添加新的工廠子類,符合開放封閉原則,克服了簡單工廠模式中缺點

 

3-3、實例引入

 定義一個抽象手機類

package com.designmode.factory.method;
/**
* 類說明 :抽象手機類
*/
public abstract class Mobile {

}

定義一個具體手機類 - 小米手機

package com.designmode.factory.method;
/**
* 類說明 :具體手機--小米手機
*/
public class XiaomiMobile extends Mobile{

}

定義一個具體手機類 - 華為手機

package com.designmode.factory.method;
/**
* 類說明 :具體手機--華為手機
*/
public class HuaweiMobile extends Mobile{

}

定義一個抽象工廠接口

package com.designmode.factory.method;
/**
* 類說明 :抽象手機生產工廠
*/
public abstract interface MobileFactory {
	
	public abstract Mobile product();
}

定義具體工廠 - 小米手機生產工廠

package com.designmode.factory.method;
/**
* 類說明 :具體工廠類 - 小米工廠
*/
public class XiaomiFactory implements MobileFactory{

	@Override
	public Mobile product() {
		System.out.println("生產小米手機.");
		return new XiaomiMobile();
	}

}

定義具體工廠 - 華為手機生產工廠

package com.designmode.factory.method;
/**
* 類說明 :具體工廠類 - 華為工廠
*/
public class HuaweiFactory implements MobileFactory{

	@Override
	public Mobile product() {
		System.out.println("生產華為手機.");
		return new HuaweiMobile();
	}
}

下面測試生產小米手機,華為手機

package com.designmode.factory.method;

/**
* 類說明 :測試
*/
public class Test {
	public static void main(String[] args) {
		MobileFactory factory = null;
		
		factory = new XiaomiFactory();
		factory.product();
		
		factory = new HuaweiFactory();
		factory.product();
	}
}

結果:

生產小米手機.
生產華為手機.

 

3-4、優缺點

優點:
  更符合開-閉原則,新增一種產品時,只需要增加相應的具體產品類和相應的工廠子類即可;

  符合單一職責原則,每個具體工廠類只負責創建對應的產品;

  總結:工廠模式可以說是簡單工廠模式的進一步抽象和拓展,在保留了簡單工廠的封裝優點的同時,讓擴展變得簡單,讓繼承變得可行,增加了多態性的體現;

缺點:
  添加新產品時,除了增加新產品類外,還要提供與之對應的具體工廠類,系統類的個數將成對增加,在一定程度上增加了系統的復雜度;同時,有更多的類需要編譯和運行,會給系統帶來一些額外的開銷;

  由於考慮到系統的可擴展性,需要引入抽象層,在客戶端代碼中均使用抽象層進行定義,增加了系統的抽象性和理解難度,且在實現時可能需要用到DOM、反射等技術,增加了系統的實現難度;

  雖然保證了工廠方法內的對修改關閉,但對於使用工廠方法的類,如果要更換另外一種產品,仍然需要修改實例化的具體工廠類;

  一個具體工廠只能創建一種具體產品;

 

3-5、應用場景

  (1) 客戶端不知道它所需要的對象的類。在工廠方法模式中,客戶端不需要知道具體產品類的類名,只需要知道所對應的工廠即可,具體的產品對象由具體工廠類創建;

  (2) 抽象工廠類通過其子類來指定創建哪個對象。在工廠方法模式中,對於抽象工廠類只需要提供一個創建產品的接口,而由其子類來確定具體要創建的對象;

4、抽象工廠模式

4-1、介紹

  抽象工廠模式為創建一組對象提供了一種解決方案。與工廠方法模式相比,抽象工廠模式中的具體工廠不只是創建一種產品,它負責創建一族產品;

    英文:Abstract Factory

  定義:提供一個創建一系列相關或相互依賴對象的接口,而無須指定它們的具體類;

 

4-2、解決的問題

  每個工廠只能創建一類產品

  即工廠方法模式的缺點

 

4-3、實例引入

 創建一個產品抽象族

package com.designmode.factory.absract;
/**
* 類說明 :抽象產品族
*/
public abstract class AbstractProduct {
	
}

創建一個手機抽象類

package com.designmode.factory.absract;
/**
* 類說明 :抽象手機類
*/
public abstract class Mobile extends AbstractProduct{

}

創建一個MP3抽象類

package com.designmode.factory.absract;
/**
* 類說明 :抽象MP3類
*/
public abstract class MP3 extends AbstractProduct{

}

創建一個具體手機類 - 小米手機

package com.designmode.factory.absract;
/**
* 類說明 :具體手機--小米手機
*/
public class XiaomiMobile extends Mobile{

}

創建一個具體手機類 - 華為手機

package com.designmode.factory.absract;
/**
* 類說明 :具體手機--華為手機
*/
public class HuaweiMobile extends Mobile{

}

創建一個具體MP3類 - 小米MP3

package com.designmode.factory.absract;
/**
* 類說明 :具體MP3--小米MP3
*/
public class XiaomiMP3 extends MP3{

}

創建一個具體MP3類 - 華為MP3

package com.designmode.factory.absract;
/**
* 類說明 :具體MP3--華為MP3
*/
public class HuaweiMP3 extends MP3{

}

創建抽象工廠類

package com.designmode.factory.absract;
/**
* 類說明 :抽象工廠類
*/
public abstract interface AbstractFactory {

	public abstract Mobile productMobile();
	
	public abstract MP3 productMP3();
}

創建具體工廠類 - 小米工廠

package com.designmode.factory.absract;
/**
* 類說明 :小米工廠類
*/
public class XiaomiFactory implements AbstractFactory{

	@Override
	public Mobile productMobile() {
		System.out.println("生產小米手機.");
		return new XiaomiMobile();
	}

	@Override
	public MP3 productMP3() {
		System.out.println("生產小米MP3.");
		return new XiaomiMP3();
	}

}

創建具體工廠類 - 華為工廠

package com.designmode.factory.absract;
/**
* 類說明 :華為工廠類
*/
public class HuaweiFactory implements AbstractFactory{

	@Override
	public Mobile productMobile() {
		System.out.println("生產華為手機.");
		return new HuaweiMobile();
	}

	@Override
	public MP3 productMP3() {
		System.out.println("生產華為MP3.");
		return new HuaweiMP3();
	}

}

下面測試一下:生產 小米手機、MP3;華為手機、MP3

package com.designmode.factory.absract;
/**
* 類說明 :測試
*/
public class Test {

	public static void main(String[] args) {
		AbstractFactory factory = null;
		
		factory = new XiaomiFactory();
		factory.productMobile();
		factory.productMP3();
		
		factory = new HuaweiFactory();
		factory.productMobile();
		factory.productMP3();
	}
}

結果:

生產小米手機.
生產小米MP3.
生產華為手機.
生產華為MP3.

 

4-4、優缺點

優點:
  1)分離接口和實現

    客戶端使用抽象工廠來創建需要的對象,而客戶端根本就不知道具體的實現是誰,客戶端只是面向產品的接口編程而已。也就是說,客戶端從具體的產品實現中解耦;

  2)使切換產品族變得容易

    因為一個具體的工廠實現代表的是一個產品族,拿上面的代碼來說,就是從“小米”到“華為”只需要切換一下具體的工廠即可;

缺點:
  1)不太容易擴展新的產品

    如果需要給整個產品族添加一個新的產品,那么就需要修改抽象工廠,這樣就會導致修改所有的工廠實現類;

 

3-5、應用場景

   為創建一組對象提供了一種解決方案;

5、總結

簡單工廠模式:

  簡單工廠類負責了所有產品的創建邏輯,當我們需要新引進一個新產品時,就不得不修改工廠類的產品創建邏輯,在產品類型較多時有可能會造成工廠類的產品創建邏輯過於負責,不利於系統的維護性和擴展性;

工廠方法模式:

  對簡單工廠模式的設計優化,簡單工廠模式中如果新增一類產品類型時,需要修改工廠靜態方法的產品創建邏輯,而使用工廠方法模式只需新擴展出一個新的工廠子類或是實現類來針對新增類型產品的創建工作、使系統具有了良好的擴展性與維護性;

抽象工廠模式:

  為創建一組對象提供了一種解決方案,與工廠方法模式相比,抽象工廠模式中的具體工廠不只是創建一種產品,它負責創建一族產品;

 

 

PS:源碼地址   https://github.com/JsonShare/DesignPattern/tree/master

   

PS:原文地址 http://www.cnblogs.com/JsonShare/p/7098376.html

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM