引入人、工廠、和斧子的問題:
(1),原始社會時,勞動社會基本沒有分工,需要斧子的人(調用者)只好自己去磨一把斧子,每個人擁有自己的斧子,如果把大家的石斧改為鐵斧,需要每個人都要學會磨鐵斧的本領,工作效率極低。
對應Java里的情形是:java程序里的調用者new一個被調用者的實例。類耦合度極高,修改維護煩瑣,效率極低。
(2),工業社會時,工廠出現,斧子不再由普通人完成,而由工廠生產,當人們需要斧子的時候,可以到工廠購買斧子,無需關心斧子是怎么制造出來的,如果廢棄鐵斧為鋼斧,只需改變工廠的制造工藝即可,制作工藝是工廠決定的,工廠生產什么斧子,工人們就得用什么斧子。
對應的Java里的情形是:Java程序的調用者可以以來簡單工廠創建被調用者,變化點被隔離到了簡單工廠里,雖然耦合度降低,但是調用者會和工廠耦合,而且需要定位自己的工廠。
(3)近代工業社會,工廠蓬勃發展,人們需要什么斧子,只需要提供一個斧子圖形,商家會按照你提供的圖形將你的斧子訂做好,送上門。
工廠模式就相當於創建實例對象的new,我們經常要根據類Class生成實例對象,如A a=new A(). 工廠模式也是用來創建實例對象的,可能多做一些工作,但會給你系統帶來更大的可擴展性和盡量少的修改量。
工廠方式封裝:
Sample有個繼承如MySample
public class Factory{
public static Sample creator(int which){
//getClass 產生Sample 一般可使用動態類裝載裝入類。
if (which==1)
return new SampleA();
else if (which==2)
return new SampleB();
}
在程序中,如果要實例化Sample時.就使用
Sample sampleA=Factory.creator(1);
在列舉個例子:
比如你寫了個應用,里面用到了數據庫的封裝,你的應用可以今后需要在不同的數據庫環境下運行,可能是oracle,db2,sql server等,那么連接數據庫的代碼是不一樣的,你用傳統的方法,就不得不進行代碼修改來適應不同的環境,非常麻煩,但是如果你采用工廠類的話,將各種可能的數據庫連接全部實現在工廠類里面,通過你配置文件的修改來達到連接的是不同的數據庫,那么你今后做遷移的時候代碼就不用進行修改了。
一、 抽象工廠(Abstract Factory)模式
抽象工廠模式是所有形態的工廠模式中最為抽象和最具一般性的一種形態。
為了方便引進抽象工廠模式,引進一個新概念:產品族(Product Family)。所謂產品族,是指位於不同產品等級結構,功能相關聯的產品組成的家族。如圖:

圖中一共有四個產品族,分布於三個不同的產品等級結構中。只要指明一個產品所處的產品族以及它所屬的等級結構,就可以唯一的確定這個產品。
引進抽象工廠模式
所謂的抽象工廠是指一個工廠等級結構可以創建出分屬於不同產品等級結構的一個產品族中的所有對象。如果用圖來描述的話,如下圖:

二、 Abstract Factory模式的結構:

圖中描述的東西用產品族描述如下:

抽象工廠(Abstract Factory)角色:擔任這個角色的是工廠方法模式的核心,它是與應用系統商業邏輯無關的。
具體工廠(Concrete Factory)角色:這個角色直接在客戶端的調用下創建產品的實例。這個角色含有選擇合適的產品對象的邏輯,而這個邏輯是與應用系統的商業邏輯緊密相關的。
抽象產品(Abstract Product)角色:擔任這個角色的類是工廠方法模式所創建的對象的父類,或它們共同擁有的接口。
具體產品(Concrete Product)角色:抽象工廠模式所創建的任何產品對象都是某一個具體產品類的實例。這是客戶端最終需要的東西,其內部一定充滿了應用系統的商業邏輯。
三、 程序舉例:
該程序演示了抽象工廠的結構,本身不具有任何實際價值。
//
Abstract Factory pattern -- Structural example
using
System;
//
"AbstractFactory"
abstract
class
AbstractFactory
{
// Methods
abstract public AbstractProductA CreateProductA();
abstract public AbstractProductB CreateProductB();
}

//
"ConcreteFactory1"
class
ConcreteFactory1 : AbstractFactory
{
// Methods
override public AbstractProductA CreateProductA()
{
return new ProductA1();
}
override public AbstractProductB CreateProductB()
{
return new ProductB1();
}
}

//
"ConcreteFactory2"
class
ConcreteFactory2 : AbstractFactory
{
// Methods
override public AbstractProductA CreateProductA()
{
return new ProductA2();
}
override public AbstractProductB CreateProductB()
{
return new ProductB2();
}
}

//
"AbstractProductA"
abstract
class
AbstractProductA
{
}

//
"AbstractProductB"
abstract
class
AbstractProductB
{
// Methods
abstract public void Interact( AbstractProductA a );
}

//
"ProductA1"
class
ProductA1 : AbstractProductA
{
}

//
"ProductB1"
class
ProductB1 : AbstractProductB
{
// Methods
override public void Interact( AbstractProductA a )
{
Console.WriteLine( this + " interacts with " + a );
}
}

//
"ProductA2"
class
ProductA2 : AbstractProductA
{
}

//
"ProductB2"
class
ProductB2 : AbstractProductB
{
// Methods
override public void Interact( AbstractProductA a )
{
Console.WriteLine( this + " interacts with " + a );
}
}

//
"Client" - the interaction environment of the products
class
Environment
{
// Fields
private AbstractProductA AbstractProductA;
private AbstractProductB AbstractProductB;
// Constructors
public Environment( AbstractFactory factory )
{
AbstractProductB = factory.CreateProductB();
AbstractProductA = factory.CreateProductA();
}
// Methods
public void Run()
{
AbstractProductB.Interact( AbstractProductA );
}
}

/// <summary>
/// ClientApp test environment
/// </summary>
class
ClientApp
{
public static void Main(string[] args)
{
AbstractFactory factory1 = new ConcreteFactory1();
Environment e1 = new Environment( factory1 );
e1.Run();
AbstractFactory factory2 = new ConcreteFactory2();
Environment e2 = new Environment( factory2 );
e2.Run();
}
}
四、 在什么情形下使用抽象工廠模式:
在以下情況下應當考慮使用抽象工廠模式:
- 一個系統不應當依賴於產品類實例如何被創建、組合和表達的細節,這對於所有形態的工廠模式都是重要的。
- 這個系統有多於一個的產品族,而系統只消費其中某一產品族。
- 同屬於同一個產品族的產品是在一起使用的,這一約束必須在系統的設計中體現出來。
- 系統提供一個產品類的庫,所有的產品以同樣的接口出現,從而使客戶端不依賴於實現。
五、 抽象工廠的起源
據說最早的應用是用來創建在不同操作系統的視窗環境下都能夠運行的系統。比如在Windows與Unix系統下都有視窗環境的構件,在每一個操作系統中,都有一個視窗構件組成的構件家族。我們可以通過一個抽象角色給出功能描述,而由具體子類給出不同操作系統下的具體實現,如圖:

可以發現上面產品類圖有兩個產品等級結構,分別是Button與Text;同時有兩個產品族:Unix產品族與Windows產品族。

系統對產品對象的創建要求由一個工廠的等級結構滿足。其中有兩個具體工廠角色,即UnixFactory和WinFactory。UnixFactory對象負責創建Unix產品族中的產品,而WinFactory負責創建Windows產品族中的產品。

顯然一個系統只能夠在某一個操作系統的視窗環境下運行,而不能同時在不同的操作系統上運行。所以,系統實際上只能消費屬於同一個產品族的產品。
在現代的應用中,抽象工廠模式的使用范圍已經大大擴大了,不再要求系統只能消費某一個產品族了。
六、 Abstract Factory模式在實際系統中的實現
Herbivore:草食動物
Carnivore:食肉動物
Bison:['baisn],美洲或歐洲的野牛
下面實際代碼演示了一個電腦游戲中創建不同動物的抽象工廠。盡管在不同大陸下動物物種是不一樣的,但動物間的關系仍然保留了下來。
//
Abstract Factory pattern -- Real World example
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
{
}

//
"AbstractProductB"
abstract
class
Carnivore
{
// Methods
abstract public void Eat( Herbivore h );
}

//
"ProductA1"
class
Wildebeest : Herbivore
{
}

//
"ProductB1"
class
Lion : Carnivore
{
// Methods
override public void Eat( Herbivore h )
{
// eat wildebeest
Console.WriteLine( this + " eats " + h );
}
}

//
"ProductA2"
class
Bison : Herbivore
{
}

//
"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()
{ 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();
}
}
抽象工廠的另外一個例子:

如何設計抽象類工廠留作思考。
七、 "開放-封閉"原則
"開放-封閉"原則要求系統對擴展開放,對修改封閉。通過擴展達到增強其功能的目的。對於涉及到多個產品族與多個產品等級結構的系統,其功能增強包括兩方面:
增加產品族:Abstract Factory很好的支持了"開放-封閉"原則。
增加新產品的等級結構:需要修改所有的工廠角色,沒有很好支持"開放-封閉"原則。
綜合起來,抽象工廠模式以一種傾斜的方式支持增加新的產品,它為新產品族的增加提供方便,而不能為新的產品等級結構的增加提供這樣的方便。


