C#設計模式(6)-Abstract Factory Pattern

 --------http://www.cnblogs.com/zhenyulu/articles/36885.html

一、 抽象工廠(Abstract Factory)模式

抽象工廠模式是所有形態的工廠模式中最爲抽象和最具一般性的一種形態。

爲了方便引進抽象工廠模式,引進一個新概念:產品族(Product Family)。所謂產品族,是指位於不同產品等級結構,功能相關聯的產品組成的家族。如圖:

 Pic44.gif

圖中一共有四個產品族,分佈於三個不同的產品等級結構中。只要指明一個產品所處的產品族以及它所屬的等級結構,就可以唯一的確定這個產品。

引進抽象工廠模式

所謂的抽象工廠是指一個工廠等級結構可以創建出分屬於不同產品等級結構的一個產品族中的所有對象。如果用圖來描述的話,如下圖:

 Pic45.gif

二、 Abstract Factory模式的結構:

 Pic46.gif

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

 Pic47.gif


抽象工廠(Abstract Factory)角色:擔任這個角色的是工廠方法模式的核心,它是與應用系統商業邏輯無關的。

具體工廠(Concrete Factory)角色:這個角色直接在客戶端的調用下創建產品的實例。這個角色含有選擇合適的產品對象的邏輯,而這個邏輯是與應用系統的商業邏輯緊密相關的。

抽象產品(Abstract Product)角色:擔任這個角色的類是工廠方法模式所創建的對象的父類,或它們共同擁有的接口。

具體產品(Concrete Product)角色:抽象工廠模式所創建的任何產品對象都是某一個具體產品類的實例。這是客戶端最終需要的東西,其內部一定充滿了應用系統的商業邏輯。


三、 程序舉例:

該程序演示了抽象工廠的結構,本身不具有任何實際價值。

None.gif// Abstract Factory pattern -- Structural example  
None.gif
using System;
None.gif
None.gif
// "AbstractFactory"
None.gif
abstract class AbstractFactory
ExpandedBlockStart.gif
{
InBlock.gif  
// Methods
InBlock.gif
  abstract public AbstractProductA CreateProductA();
InBlock.gif  
abstract public AbstractProductB CreateProductB();
ExpandedBlockEnd.gif}

None.gif
None.gif
// "ConcreteFactory1"
None.gif
class ConcreteFactory1 : AbstractFactory
ExpandedBlockStart.gif
{
InBlock.gif  
// Methods
InBlock.gif
  override public AbstractProductA CreateProductA()
ExpandedSubBlockStart.gif  
{
InBlock.gif    
return new ProductA1();
ExpandedSubBlockEnd.gif  }

InBlock.gif  
override public AbstractProductB CreateProductB()
ExpandedSubBlockStart.gif  
{
InBlock.gif    
return new ProductB1();
ExpandedSubBlockEnd.gif  }

ExpandedBlockEnd.gif}

None.gif
None.gif
// "ConcreteFactory2"
None.gif
class ConcreteFactory2 : AbstractFactory
ExpandedBlockStart.gif
{
InBlock.gif  
// Methods
InBlock.gif
  override public AbstractProductA CreateProductA()
ExpandedSubBlockStart.gif  
{
InBlock.gif    
return new ProductA2();
ExpandedSubBlockEnd.gif  }

InBlock.gif
InBlock.gif  
override public AbstractProductB CreateProductB()
ExpandedSubBlockStart.gif  
{
InBlock.gif    
return new ProductB2();
ExpandedSubBlockEnd.gif  }

ExpandedBlockEnd.gif}

None.gif
None.gif
// "AbstractProductA"
None.gif
abstract class AbstractProductA
ExpandedBlockStart.gif
{
ExpandedBlockEnd.gif}

None.gif
None.gif
// "AbstractProductB"
None.gif
abstract class AbstractProductB
ExpandedBlockStart.gif
{
InBlock.gif  
// Methods
InBlock.gif
  abstract public void Interact( AbstractProductA a );
ExpandedBlockEnd.gif}

None.gif
None.gif
// "ProductA1"
None.gif
class ProductA1 : AbstractProductA
ExpandedBlockStart.gif
{
ExpandedBlockEnd.gif}

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

ExpandedBlockEnd.gif}

None.gif
None.gif
// "ProductA2"
None.gif
class ProductA2 : AbstractProductA
ExpandedBlockStart.gif
{
ExpandedBlockEnd.gif}

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

ExpandedBlockEnd.gif}

None.gif
None.gif
// "Client" - the interaction environment of the products
None.gif
class Environment
ExpandedBlockStart.gif
{
InBlock.gif  
// Fields
InBlock.gif
  private AbstractProductA AbstractProductA;
InBlock.gif  
private AbstractProductB AbstractProductB;
InBlock.gif
InBlock.gif  
// Constructors
InBlock.gif
  public Environment( AbstractFactory factory )
ExpandedSubBlockStart.gif  
{
InBlock.gif    AbstractProductB 
= factory.CreateProductB();
InBlock.gif    AbstractProductA 
= factory.CreateProductA();
ExpandedSubBlockEnd.gif  }

InBlock.gif 
InBlock.gif  
// Methods
InBlock.gif
  public void Run()
ExpandedSubBlockStart.gif  
{
InBlock.gif    AbstractProductB.Interact( AbstractProductA );
ExpandedSubBlockEnd.gif  }

ExpandedBlockEnd.gif}

None.gif
ExpandedBlockStart.gif
/// <summary>
InBlock.gif
/// ClientApp test environment
ExpandedBlockEnd.gif
/// </summary>

None.gifclass ClientApp
ExpandedBlockStart.gif
{
InBlock.gif  
public static void Main(string[] args)
ExpandedSubBlockStart.gif  
{
InBlock.gif    AbstractFactory factory1 
= new ConcreteFactory1();
InBlock.gif    Environment e1 
= new Environment( factory1 );
InBlock.gif    e1.Run();
InBlock.gif
InBlock.gif    AbstractFactory factory2 
= new ConcreteFactory2();
InBlock.gif    Environment e2 
= new Environment( factory2 );
InBlock.gif    e2.Run();
ExpandedSubBlockEnd.gif  }

ExpandedBlockEnd.gif}

 


四、 在什麼情形下使用抽象工廠模式:

在以下情況下應當考慮使用抽象工廠模式:

  • 一個系統不應當依賴於產品類實例如何被創建、組合和表達的細節,這對於所有形態的工廠模式都是重要的。
  • 這個系統有多於一個的產品族,而系統只消費其中某一產品族。
  • 同屬於同一個產品族的產品是在一起使用的,這一約束必須在系統的設計中體現出來。
  • 系統提供一個產品類的庫,所有的產品以同樣的接口出現,從而使客戶端不依賴於實現。

五、 抽象工廠的起源

據說最早的應用是用來創建在不同操作系統的視窗環境下都能夠運行的系統。比如在Windows與Unix系統下都有視窗環境的構件,在每一個操作系統中,都有一個視窗構件組成的構件家族。我們可以通過一個抽象角色給出功能描述,而由具體子類給出不同操作系統下的具體實現,如圖:

 Pic48.gif

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

 Pic49.gif

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

 Pic50.gif

顯然一個系統只能夠在某一個操作系統的視窗環境下運行,而不能同時在不同的操作系統上運行。所以,系統實際上只能消費屬於同一個產品族的產品。

在現代的應用中,抽象工廠模式的使用範圍已經大大擴大了,不再要求系統只能消費某一個產品族了。


六、 Abstract Factory模式在實際系統中的實現

Herbivore:草食動物
Carnivore:食肉動物
Bison:['baisn],美洲或歐洲的野牛

下面實際代碼演示了一個電腦遊戲中創建不同動物的抽象工廠。儘管在不同大陸下動物物種是不一樣的,但動物間的關係仍然保留了下來。

None.gif// Abstract Factory pattern -- Real World example  
None.gif
using System;
None.gif
None.gif
// "AbstractFactory"
None.gif
abstract class ContinentFactory
ExpandedBlockStart.gif
{
InBlock.gif  
// Methods
InBlock.gif
  abstract public Herbivore CreateHerbivore();
InBlock.gif  
abstract public Carnivore CreateCarnivore();
ExpandedBlockEnd.gif}

None.gif
None.gif
// "ConcreteFactory1"
None.gif
class AfricaFactory : ContinentFactory
ExpandedBlockStart.gif
{
InBlock.gif  
// Methods
InBlock.gif
  override public Herbivore CreateHerbivore()
ExpandedSubBlockStart.gif  
return new Wildebeest(); }
InBlock.gif
InBlock.gif  
override public Carnivore CreateCarnivore()
ExpandedSubBlockStart.gif  
return new Lion(); }
ExpandedBlockEnd.gif}

None.gif
None.gif
// "ConcreteFactory2"
None.gif
class AmericaFactory : ContinentFactory
ExpandedBlockStart.gif
{
InBlock.gif  
// Methods
InBlock.gif
  override public Herbivore CreateHerbivore()
ExpandedSubBlockStart.gif  
return new Bison(); }
InBlock.gif
InBlock.gif  
override public Carnivore CreateCarnivore()
ExpandedSubBlockStart.gif  
return new Wolf(); }
ExpandedBlockEnd.gif}

None.gif
None.gif
// "AbstractProductA"
None.gif
abstract class Herbivore
ExpandedBlockStart.gif
{
ExpandedBlockEnd.gif}

None.gif
None.gif
// "AbstractProductB"
None.gif
abstract class Carnivore
ExpandedBlockStart.gif
{
InBlock.gif  
// Methods
InBlock.gif
  abstract public void Eat( Herbivore h );
ExpandedBlockEnd.gif}

None.gif
None.gif
// "ProductA1"
None.gif
class Wildebeest : Herbivore
ExpandedBlockStart.gif
{
ExpandedBlockEnd.gif}

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

ExpandedBlockEnd.gif}

None.gif
None.gif
// "ProductA2"
None.gif
class Bison : Herbivore
ExpandedBlockStart.gif
{
ExpandedBlockEnd.gif}

None.gif
None.gif
// "ProductB2"
None.gif
class Wolf : Carnivore
ExpandedBlockStart.gif
{
InBlock.gif  
// Methods
InBlock.gif
  override public void Eat( Herbivore h )
ExpandedSubBlockStart.gif  
{
InBlock.gif    
// Eat bison
InBlock.gif
    Console.WriteLine( this + " eats " + h );
ExpandedSubBlockEnd.gif  }

ExpandedBlockEnd.gif}

None.gif
None.gif
// "Client"
None.gif
class AnimalWorld
ExpandedBlockStart.gif
{
InBlock.gif  
// Fields
InBlock.gif
  private Herbivore herbivore;
InBlock.gif  
private Carnivore carnivore;
InBlock.gif
InBlock.gif  
// Constructors
InBlock.gif
  public AnimalWorld( ContinentFactory factory )
ExpandedSubBlockStart.gif  
{
InBlock.gif    carnivore 
= factory.CreateCarnivore();
InBlock.gif    herbivore 
= factory.CreateHerbivore();
ExpandedSubBlockEnd.gif  }

InBlock.gif
InBlock.gif  
// Methods
InBlock.gif
  public void RunFoodChain()
ExpandedSubBlockStart.gif  
{ carnivore.Eat(herbivore); }
ExpandedBlockEnd.gif}

None.gif
ExpandedBlockStart.gif
/// <summary>
InBlock.gif
///  GameApp test class
ExpandedBlockEnd.gif
/// </summary>

None.gifclass GameApp
ExpandedBlockStart.gif
{
InBlock.gif  
public static void Main( string[] args )
ExpandedSubBlockStart.gif  
{
InBlock.gif    
// Create and run the Africa animal world
InBlock.gif
    ContinentFactory africa = new AfricaFactory();
InBlock.gif    AnimalWorld world 
= new AnimalWorld( africa );
InBlock.gif    world.RunFoodChain();
InBlock.gif
InBlock.gif    
// Create and run the America animal world
InBlock.gif
    ContinentFactory america = new AmericaFactory();
InBlock.gif    world 
= new AnimalWorld( america );
InBlock.gif    world.RunFoodChain();
ExpandedSubBlockEnd.gif  }

ExpandedBlockEnd.gif}

抽象工廠的另外一個例子:

Pic51.gif

如何設計抽象類工廠留作思考。


七、 "開放-封閉"原則

"開放-封閉"原則要求系統對擴展開放,對修改封閉。通過擴展達到增強其功能的目的。對於涉及到多個產品族與多個產品等級結構的系統,其功能增強包括兩方面:

增加產品族:Abstract Factory很好的支持了"開放-封閉"原則。

增加新產品的等級結構:需要修改所有的工廠角色,沒有很好支持"開放-封閉"原則。

綜合起來,抽象工廠模式以一種傾斜的方式支持增加新的產品,它爲新產品族的增加提供方便,而不能爲新的產品等級結構的增加提供這樣的方便。


參考文獻:
閻宏,《Java與模式》,電子工業出版社
[美]James W. Cooper,《C#設計模式》,電子工業出版社
[美]Alan Shalloway  James R. Trott,《Design Patterns Explained》,中國電力出版社
[美]Robert C. Martin,《敏捷軟件開發-原則、模式與實踐》,清華大學出版社
[美]Don Box, Chris Sells,《.NET本質論 第1卷:公共語言運行庫》,中國電力出版社

發佈了72 篇原創文章 · 獲贊 2 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章