各種工廠模式詳解
簡單工廠模式
一般是一個工廠類對應多個具體產品類,通過外界向工廠傳遞的引數來判斷建立某一個具體的產品類。 既然被叫做“工廠”當然不能只生產一樣產品,簡單工廠只生產同一家族的產品,具體的說就是簡單工廠建立的類都是從同一個抽象繼承下來的。根據客戶不同的需求來建立不同的類,可是被建立的類都必須滿足一個條件:必須是同一家族的產品(從同一個根繼承下來的子類)。例如:有一個生產水果的簡單工廠,根據客戶的需要可以生產蘋果、橘子、葡萄、香蕉,但是必須滿足一個要求,就是它只能生產水果。如果客戶需要機器、房屋等東西,那麼這些要求都將不能被滿足. 簡單工廠結構簡單,由三個部分構成:類工廠 : 是最核心的部分,作為簡單工廠對外使用的介面,負責實現建立例項的邏輯抽象產品: 工廠生產所有的產品的抽象 ,可能是抽象類或介面,也可能是普通的基類具體產品: 簡單工廠建立的具體類的例項舉例如下:
public interface Fruit{ }
public class Apple implement Fruit{ }
public class Orange implement Fruit{ }
public class SimpleFactory{
public static final APPLE = 1;
public static final ORANGE = 2;
public Fruit createFruit(int type){
switch(type){
case APPLE: return new Orange();
case ORANGE: return new Apple();
}
}
評價: Fruit 就是抽象產品, Apple 和Orange是具體產品,SimpleFactory為類工廠,是最核心的功能.所有的核心功能都是靠工廠類實現的,如根據條件判斷建立哪種具體的產品,以及實際建立產品等。在這一點上違背了“物件的職責均衡分佈的原則”,因為功能過於集中在工廠類本身,隨著簡單工廠生產的產品種類的增加,使其業務邏輯無限的增加,會使其本身越來越複雜而難於維護和擴充套件。缺點:隨著產品種類增加使其越來越難以使用優點:與工廠方法和抽象工廠相比, 其優勢是簡單易用, 只靠一個工廠類就可以建立所有的產品類適用場合:當工廠只生產同一品種的具體產品,而且產品數量有限的時候,可以考慮使用此工廠模式。
Factory Method模式
在工廠父類中定義一個標準的方法用來生產產品。一般來說這個方法應該被宣告成抽象方法(當工廠父類是抽象類的時候),或介面中的空方法(工廠父類僅僅是介面),這個方法只有方法的定義並沒有具體實現。將這個方法的具體實現延遲到子類中來完成。這樣父類只需要負責取出抽象的產品,而不必關心怎麼去建立具體的產品和到底建立哪一種具體的產品。至於究竟應該建立何種具體的產品由具體的子類負責決定。考慮到簡單工廠模式中因為功能過於集中在工廠類中而產生的種種的缺陷,在Factory Method模式中把工廠類生產產品的定義和生產具體產品的實現拆分開,用一個類的繼承體系來消除工廠類中複雜的邏輯判斷語句。從而使類的職責、能力能夠比較均衡的分佈。 Factory Method結構由四個部分構成:抽象類工廠 : 定義統一的介面來建立產品。具體類工廠 :實現建立具體產品類的類工廠(一般為多個)。抽象產品: 工廠生產所有產品的抽象 ,可能是抽象類或介面,也可能是普通的基類。具體產品: Factory Method建立的具體類的例項(多個)。舉例如下:
public interface AbstractFactory{
public Fruit create();
}
public class AppleFactory implement AbstractFactory{
public Fruit create(){
return new Apple();
}
}
public class OrangeFactory implement AbstractFactory{
public Fruit create(){
return new Orange();
}
}
評價: 如此, 客戶端程式可以通過更改建立產品的工廠類的子類,用統一的方式建立不同的具體產品。即使需要增加生產新的產品也不需要修改現有的程式碼,只須建立一個生產這個產品的子工廠類。前提是這個新產品和原來工廠生產的產品必須是一類的(介面必須是一致的)。優勢: 因為生產具體產品是靠子工廠類實現的,增加新的產品不會影響到現有的程式,從這點上來看程式是“閉合”的。修改子工廠類的實現方式也不會影響客戶端的使用。
缺點: 在工廠方法模式中因為所有的具體產品都是同一個父類(或介面)繼承下來的,它只能生產“同一種類”的具體產品。比如上例:這個工廠只能生產各種類的Fruit, 如果你需要食物、汽車和電子產品的話,那麼上面的工廠方法模式是不可能滿足你的。 還有因為在客戶端呼叫此模式生產產品的時候是直接使用的子工廠類,如果需要修改生產產品的種類的話,則需要修改客戶端的程式碼,這點有些不滿足面向抽象的原則。如果要解決這種問題那就需要和別的設計模式結合起來使用。
Abstract Factory模式
上面講的工廠模式並不能夠生產不同種類的產品,為了解決這個問題,就需要使用Abstract Factory模式 。抽象工廠模式和工廠方法模式有了很大的不同。Abstract Factory模式的目的提供一個建立一系列相關或相互依賴物件的介面,而無需指定它們具體的類。使用抽象工廠建立的產品是“產品族”,也就是兩族或兩族以上的產品,並且這些產品是“相關”的、“相互依賴”的。如果只生產一族產品,抽象工廠模式就完全退化成了工廠方法模式。 所以抽象工廠使用的前提條件有兩個:
1、生產產品族大於一族,只有生產兩族以上的產品才使用抽象工廠。
2、產品之間有特殊的相關或依賴關係,產品之間最少應該有兩種關係; 縱向來看每種產品組內部產品之間有繼承關係。例如:產品AbstractProductA與ProductA1和ProductA2之間有繼承關係是同一產品族產品; 橫向來看兩個產品族之間的產品也應該有一一對應關係,例如:ProductA1與ProductB1之間,或ProductA2與ProductB2之間的對應關係。在只滿足條件1的前提下,感覺應該使用多個工廠方法模式來代替抽象工廠模式,這樣使用起來應該會方便一些。舉例如下:
using System; // "AbstractFactory"
abstract class ContinentFactory{ // Methods
abstract public Herbivore CreateHerbivore();
abstract public Carnivore CreateCarnivore();
} // "ConcreteFactory1"
class AfricaFactory : ContinentFactory{ // Methods
override public Herbivore CreateHerbivore()
{
return new Wildebeest();
}
override public Carnivore CreateCarnivore()
{
return new Lion();
}
} // "ConcreteFactory2"
class AmericaFactory : ContinentFactory{ // Methods
override public Herbivore CreateHerbivore() {
return new Bison();
}
override public Carnivore CreateCarnivore() {
return new Wolf();
}
} // "AbstractProductA"
abstract class Herbivore{
abstract public void Eat();
} // "AbstractProductB"
abstract class Carnivore{ // Methods
abstract public void Eat( Herbivore h );
} // "ProductA1"
class Wildebeest : Herbivore{
override public void Eat()
{
Console.WriteLine(this + "eats Africa's Glass");
}
} // "ProductB1"
class Lion : Carnivore{ // Methods
override public void Eat( Herbivore h ) { // eat wildebeest
Console.WriteLine( this + " eats " + h );
}
} // "ProductA2"
class Bison : Herbivore{
override public void Eat() {
Console.WriteLine(this + "eats American's Glass");
}
} // "ProductB2"
class Wolf : Carnivore{ // Methods
override public void Eat( Herbivore h ) { // Eat bison
Console.WriteLine( this + " eats " + h );
}
} // "Client"
class AnimalWorld{ // Fields
private Herbivore herbivore;
private Carnivore carnivore; // Constructors
public AnimalWorld( ContinentFactory factory ) {
carnivore = factory.CreateCarnivore();
herbivore = factory.CreateHerbivore();
} // Methods
public void RunFoodChain() {
herbivore.Eat();
carnivore.Eat( herbivore );
}
}
/// <summary>///
GameApp test class/// </summary>
class GameApp{
public static void Main( string[] args ) { // Create and run the Africa animal world
ContinentFactory africa = new AfricaFactory();
AnimalWorld world = new AnimalWorld( africa );
world.RunFoodChain(); // Create and run the America animal world
ContinentFactory america = new AmericaFactory();
world = new AnimalWorld( america );
world.RunFoodChain();
Console.Read(); }
}