【設計模式】C#設計模式:工廠方法模式

【設計模式】面向對象設計七大原則
【設計模式】設計模式概念和分類
【設計模式】C#設計模式:單例模式
【設計模式】C#設計模式:工廠方法模式
【設計模式】C#設計模式:抽象工廠模式

簡單工廠模式

簡單工廠模式(Simple Factory Pattern):又稱爲靜態工廠方法(Static Factory Method)模式,它屬於類創建型模式。在簡單工廠模式中,可以根據參數的不同返回不同類的實例。簡單工廠模式專門定義一個類來負責創建其他類的實例,被創建的實例通常都具有共同的父類。

簡單工廠模式包含如下角色:

(1)工廠(Factory):提供了創建產品的工廠方法,負責具體產品的創建;
(2)抽象產品(Product):定義了產品的規範,描述了產品的主要特徵和功能;
(3)具體產品(Concrete Product):實現了抽象產品角色所定義的接口,有工廠來創建;

模式分析

將對象的創建和對象本身業務處理分離可以降低系統的耦合度,使得兩者修改起來都相對容易。
在調用工廠類的工廠方法時,由於工廠方法是靜態方法,使用起來很方便,可通過類名直接調用,而且只需要傳入一個簡單的參數即可。
簡單工廠模式最大的問題在於工廠類的職責相對過重,增加新的產品需要修改工廠類的判斷邏輯,這一點與開閉原則是相違背的。
簡單工廠模式的要點在於:當你需要什麼,只需要傳入一個正確的參數,就可以獲取你所需要的對象,而無須知道其創建細節。

public enum PhoneBrand
{
	HUAWEI,
	MI,
	OPPO,
	VIVO,
}

/// <summary>
/// 手機抽象產品
/// </summary>
public class MobilePhone
{
	public virtual void SendMessage() { Debug.Log("MobilePhone Hello"); }
	public virtual void Telephone() { }
}

/// <summary>
/// 手機具體產品
/// </summary>
public class PhoneHUAWEI: MobilePhone
{
	public override void SendMessage()
	{
		Debug.Log("HUAWEI Hello");
	}
}

public class PhoneOPPO : MobilePhone
{
	public override void SendMessage()
	{
		Debug.Log("PhoneOPPO Hello");
	}
}
public class PhoneMI : MobilePhone { }
public class PhoneVIVO : MobilePhone { }

/// <summary>
/// 生產工廠
/// </summary>
public class Foundries
{
	public MobilePhone Product(PhoneBrand brand)
	{
		MobilePhone mobilePhone = null;
		switch (brand)
		{
			case PhoneBrand.HUAWEI:
				mobilePhone = new PhoneHUAWEI();
				break;
			case PhoneBrand.MI:
				mobilePhone = new PhoneMI();
				break;
			case PhoneBrand.OPPO:
				mobilePhone = new PhoneOPPO();
				break;
			case PhoneBrand.VIVO:
				mobilePhone = new PhoneVIVO();
				break;
		}
		return mobilePhone;
	}
}

/// <summary>
/// 工廠使用案列
/// </summary>
public class Employ
{
	List<PhoneBrand> phoneBrands;

	/// <summary>
	/// 下訂單
	/// </summary>
	public void PlaceAnOrder()
	{
		phoneBrands = new List<PhoneBrand>();
		phoneBrands.Add(PhoneBrand.HUAWEI);
		phoneBrands.Add(PhoneBrand.OPPO);
		ProductionOrder(phoneBrands);
	}

	/// <summary>
	/// 手機生產訂單
	/// </summary>
	public void ProductionOrder(List<PhoneBrand> phoneBrands)
	{
		Foundries foundries = new Foundries();
		MobilePhone mobile;
		for (int i = 0; i < phoneBrands.Count; i++)
		{
			mobile = foundries.Product(phoneBrands[i]);
			mobile.SendMessage();
		}
		phoneBrands.Clear();
		phoneBrands = null;
	}
}

模式優點

(1)工廠類含有必要的判斷邏輯,可以決定在什麼時候創建哪一個產品類的實例,客戶端可以免除直接創建產品對象的責任,而僅僅“消費”產品;簡單工廠模式通過這種做法實現了對責任的分割,它提供了專門的工廠類用於創建對象。
(2)客戶端無須知道所創建的具體產品類的類名,只需要知道具體產品類所對應的參數即可,對於一些複雜的類名,通過簡單工廠模式可以減少使用者的記憶量。
(3)通過引入配置文件,可以在不修改任何客戶端代碼的情況下更換和增加新的具體產品類,在一定程度上提高了系統的靈活性。

模式缺點

(1)由於工廠類集中了所有產品創建邏輯,一旦不能正常工作,整個系統都要受到影響。
(2)使用簡單工廠模式將會增加系統中類的個數,在一定程序上增加了系統的複雜度和理解難度。
(3)系統擴展困難,一旦添加新產品就不得不修改工廠邏輯,在產品類型較多時,有可能造成工廠邏輯過於複雜,不利於系統的擴展和維護。
(4)簡單工廠模式由於使用了靜態工廠方法,造成工廠角色無法形成基於繼承的等級結構。

簡單工廠模式通常適用於以下場景:

(1)工廠類負責創建的對象比較少:由於創建的對象較少,不會造成工廠方法中的業務邏輯太過複雜。
(2)客戶端只知道傳入工廠類的參數,對於如何創建對象不關心:客戶端既不需要關心創建細節,甚至連類名都不需要記住,只需要知道類型所對應的參數。

簡單工廠模式的不足

在簡單工廠模式中,只提供了一個工廠類,該工廠類處於對產品類進行實例化的中心位置,它知道每一個產品對象的創建細節,並決定何時實例化哪一個產品類。簡單工廠模式最大的缺點是當有新產品要加入到系統中時,必須修改工廠類,加入必要的處理邏輯,這違背了“開閉原則”。在簡單工廠模式中,所有的產品都是由同一個工廠創建,工廠類職責較重,業務邏輯較爲複雜,具體產品與工廠類之間的耦合度高,嚴重影響了系統的靈活性和擴展性,而工廠方法模式則可以很好地解決這一問題。

工廠方法模式

工廠方法模式(Factory Method Pattern)又稱爲工廠模式,也叫虛擬構造器(Virtual Constructor)模式或者多態工廠(Polymorphic Factory)模式,它屬於類創建型模式。在工廠方法模式中,工廠父類負責定義創建產品對象的公共接口,而工廠子類則負責生成具體的產品對象,這樣做的目的是將產品類的實例化操作延遲到工廠子類中完成,即通過工廠子類來確定究竟應該實例化哪一個具體產品類。

工廠方法模式的主要角色如下:

(1)抽象工廠(Abstract Factory):提供了創建產品的接口,調用者通過它訪問具體工廠的工廠方法 newProduct() 來創建產品;
(2)具體工廠(Concrete Factory):主要是實現抽象工廠中的抽象方法,具體產品的創建;
(3)抽象產品(Product):定義了產品的規範,描述了產品的主要特徵和功能;
(4)具體產品(Concrete Product):實現了抽象產品角色所定義的接口,有具體工廠來創建,它同具體工廠之間一一對應。

模式分析

工廠方法模式是簡單工廠模式的進一步抽象和推廣。由於使用了面向對象的多態性,工廠方法模式保持了簡單工廠模式的優點,而且克服了它的缺點。在工廠方法模式中,核心的工廠類不再負責所有產品的創建,而是將具體創建工作交給子類去做。這個核心類僅僅負責給出具體工廠必須實現的接口,而不負責哪一個產品類被實例化這種細節,這使得工廠方法模式可以允許系統在不修改工廠角色的情況下引進新產品。
當系統擴展需要添加新的產品對象時,僅僅需要添加一個具體產品對象以及一個具體工廠對象,原有工廠對象不需要進行任何修改,也不需要修改客戶端,很好地符合了“開閉原則”。而簡單工廠模式在添加新產品對象後不得不修改工廠方法,擴展性不好。工廠方法模式退化後可以演變成簡單工廠模式。

public enum PhoneBrand
{
	HUAWEI,
	MI,
	OPPO,
	VIVO,
}

/// <summary>
/// 手機抽象產品
/// </summary>
public class MobilePhone
{
	public virtual void SendMessage() { Debug.Log("MobilePhone Hello"); }
	public virtual void Telephone() { }
}

/// <summary>
/// 手機具體產品
/// </summary>
public class PhoneHUAWEI: MobilePhone
{
	public override void SendMessage()
	{
		Debug.Log("HUAWEI Hello");
	}
}

public class PhoneOPPO : MobilePhone
{
	public override void SendMessage()
	{
		Debug.Log("PhoneOPPO Hello");
	}
}
public class PhoneMI : MobilePhone { }
public class PhoneVIVO : MobilePhone { }

/// <summary>
/// 抽象工廠
/// </summary>
public abstract class PhoneFoundries
{
	public abstract MobilePhone Product(PhoneBrand brand);
}

/// <summary>
/// HUAWEI生產工廠
/// </summary>
public class FoundriesHUAWEI : PhoneFoundries
{
	public override MobilePhone Product(PhoneBrand brand)
	{
		return new PhoneHUAWEI();
	}
}

/// <summary>
/// OPPO生產工廠
/// </summary>
public class FoundriesOPPO : PhoneFoundries
{
	public override MobilePhone Product(PhoneBrand brand)
	{
		return new PhoneOPPO();
	}
}

/// <summary>
/// 工廠使用案列
/// </summary>
public class Employ
{
	List<PhoneBrand> phoneBrands;

	/// <summary>
	/// 下訂單
	/// </summary>
	public void PlaceAnOrder()
	{
		phoneBrands = new List<PhoneBrand>();
		phoneBrands.Add(PhoneBrand.HUAWEI);
		phoneBrands.Add(PhoneBrand.OPPO);
		ProductionOrder(phoneBrands);
	}

	/// <summary>
	/// 手機生產訂單
	/// </summary>
	public void ProductionOrder(List<PhoneBrand> phoneBrands)
	{
		PhoneFoundries foundries;
		MobilePhone mobile;

		for (int i = 0; i < phoneBrands.Count; i++)
		{
			switch (phoneBrands[i])
			{
				case PhoneBrand.HUAWEI:
					foundries = new FoundriesHUAWEI();
					break;
				case PhoneBrand.OPPO:
					foundries = new FoundriesOPPO();
					break;
				default:
					continue;
			}
			mobile = foundries.Product(phoneBrands[i]);
			mobile.SendMessage();
		}
		phoneBrands.Clear();
		phoneBrands = null;
	}
}

模式優點

(1)在工廠方法模式中,工廠方法用來創建客戶所需要的產品,同時還向客戶隱藏了哪種具體產品類將被實例化這一細節,用戶只需要關心所需產品對應的工廠,無須關心創建細節,甚至無須知道具體產品類的類名。
(2)基於工廠角色和產品角色的多態性設計是工廠方法模式的關鍵。它能夠使工廠可以自主確定創建何種產品對象,而如何創建這個對象的細節則完全封裝在具體工廠內部。工廠方法模式之所以又被稱爲多態工廠模式,是因爲所有的具體工廠類都具有同一抽象父類。
(3) 使用工廠方法模式的另一個優點是在系統中加入新產品時,無須修改抽象工廠和抽象產品提供的接口,無須修改客戶端,也無須修改其他的具體工廠和具體產品,而只要添加一個具體工廠和具體產品就可以了。這樣,系統的可擴展性也就變得非常好,完全符合“開閉原則”。

模式缺點

(1)在添加新產品時,需要編寫新的具體產品類,而且還要提供與之對應的具體工廠類,系統中類的個數將成對增加,在一定程度上增加了系統的複雜度,有更多的類需要編譯和運行,會給系統帶來一些額外的開銷。
(2)由於考慮到系統的可擴展性,需要引入抽象層,在客戶端代碼中均使用抽象層進行定義,增加了系統的抽象性和理解難度,且在實現時可能需要用到DOM、反射等技術,增加了系統的實現難度。

工廠方法模式通常適用於以下場景:

(1)一個類不知道它所需要的對象的類:在工廠方法模式中,客戶端不需要知道具體產品類的類名,只需要知道所對應的工廠即可,具體的產品對象由具體工廠類創建;客戶端需要知道創建具體產品的工廠類。
(2)一個類通過其子類來指定創建哪個對象:在工廠方法模式中,對於抽象工廠類只需要提供一個創建產品的接口,而由其子類來確定具體要創建的對象,利用面向對象的多態性和里氏代換原則,在程序運行時,子類對象將覆蓋父類對象,從而使得系統更容易擴展。
(3)將創建對象的任務委託給多個工廠子類中的某一個,客戶端在使用時可以無須關心是哪一個工廠子類創建產品子類,需要時再動態指定,可將具體工廠類的類名存儲在配置文件或數據庫中。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章