我所理解的設計模式(C++實現)——抽象工廠模式(Abstract Factory Pattern)

LCL_data發表於2013-03-28

解決的問題:

       在系統裡a,b,c三個元件必須同時使用,但是a的同類 a1和a2這三種方法有共同特點但是是互斥的,b,b1,b2和c,c1,c2和a/a1/a2是一樣的。就比如說建立在不同作業系統的視窗環境下都能夠執行的系統時,Unix下面有unixButton和 unixText,Win下面也有winButton和winText,unixButton和unixText必須在一個系統unix裡面用,而winButton和winText只能在Win下面用。但是winButton和unixButton這兩種東西都是有相同的特點的,比如說按下去之後會觸發事件,比如說他上面有文字描述等等,但是winButton和unixButton卻又是不可以混用的。

     那麼此問題就可以用抽象工廠很好的解決:
     在抽象工廠模式中如何選擇使用 winButton ,winText,有具體的工廠類winFactory來負責,因為他們含有選擇合適的產品物件的邏輯,所以是與應用系統的商業邏輯緊密相關的。而抽象工廠類來負責定義介面,他才是抽象工廠模式的核心。
     而winButton/macButton則是一種產品族,有共同的特點,他們具體特點有抽象產品類或者介面來定義和描述。但是他們具體的實現有具體的產品類負責,這些是客戶端最終想要的東西,所以其內部一定充滿了應用系統的商業邏輯(觸發邏輯/樣式邏輯等)。

類圖結構:    



樣例實現:

// CplusplusAbstractFactory.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include<typeinfo>
// "AbstractProductA" 草食動物
class Herbivore
{
};

// "AbstractProductB" 食肉動物
class Carnivore
{
public:
	// Methods
	virtual void Eat( Herbivore *h ) {};
};

// "ProductA1"
class Wildebeest : public Herbivore
{
};

// "ProductA2"
class Bison : public Herbivore
{
};

// "ProductB1"
class Lion : public Carnivore
{

public:
	// Methods
	void Eat( Herbivore *h )
	{
		// eat wildebeest	 
		printf("Lion eats %s\n",typeid(h).name());
	}
};

// "ProductB2"
class Wolf : public Carnivore
{

public:
	// Methods
	void Eat( Herbivore *h )
	{
		// Eat bison
		printf("Wolf eats %s\n",typeid(h).name());
	}
};

// "AbstractFactory"
class ContinentFactory
{
public:
	// Methods
	virtual Herbivore* CreateHerbivore()
	{
		return new Herbivore();
	}
	virtual Carnivore* CreateCarnivore()
	{
		return new Carnivore();
	}
};

// "ConcreteFactory1"
class AfricaFactory : public ContinentFactory
{
public:
	// Methods
	Herbivore* CreateHerbivore()
	{ 
		return new Wildebeest(); 
	}

	Carnivore* CreateCarnivore()
	{ 
		return new Lion(); 
	}
};

// "ConcreteFactory2"
class AmericaFactory : public ContinentFactory
{
public:
	// Methods
	Herbivore* CreateHerbivore()
	{ 
		return new Bison(); 
	}

	Carnivore* CreateCarnivore()
	{ 
		return new Wolf(); 
	}
};



// "Client"
class AnimalWorld
{
private:
	// Fields
	Herbivore* herbivore;
	Carnivore* carnivore;

public:
	// Constructors
	AnimalWorld( ContinentFactory *factory )
	{
		carnivore = factory->CreateCarnivore();
		herbivore = factory->CreateHerbivore();
	}

	// Methods
	void RunFoodChain()
	{ 
		carnivore->Eat(herbivore); 
	}
};


int _tmain(int argc, _TCHAR* argv[])
{
	// 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();

	return 0;
}

“開放-封閉”原則:


抽象工廠可以很好的應對增加新產品族的問題(即a4/b4/c4),且符合“開放-封閉”原則,但是若是增加新的產品結構的話(即d/d1/d2),就是說a/b/c/d這4中方法必須同時使用了,那就必須修改工廠角色。不符合“開放-封閉”原則。綜合來講,抽象工廠模式以一種傾斜的方式支援增加新的產品,它為新產品族的增加提供方便,而不能為新的產品結構的增加提供這樣的方便。

實現要點:

  • 在抽象工廠模式中,選用哪種產品族的問題,需要採用工廠方法或簡單工廠模式來配合解決。
  • 抽象工廠模式和工廠方法模式一樣,都把物件的建立延遲到了他的子類中。
  • 具體的工廠類可以設計成單例類,他只向外界提供自己唯一的例項。

與其他工廠模式的聯絡和異同:

  • 抽象工廠模式中的具體工廠負責生產一個產品族的產品。而產品族的增加只需要增加與其對應的具體工廠。
  • 3種工廠模式都是建立型模式,都是建立物件的,但都把產品具體建立的過程給隱藏了。
  • 工廠方法模式是針對一種產品結構,而抽象工廠模式是針對多種產品結構。

適用性:

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

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

應用場景:

  • 支援多種觀感標準的使用者介面工具箱(Kit)。
  • 遊戲開發中的多風格系列場景,比如道路,房屋,管道等。

相關文章