五.创建型设计模式——Abstract Factory Pattern(抽象工厂模式)

  • 定义

  提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。抽象工厂(Abstract Factory)模式又称为Kit模式,属于对象创建型模式。

  抽象工厂模式与工厂方法模式最大的区别在于:工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则针对的是多个产品等级结构。正因如此,在抽象工厂模式中经常会用到产品族(Product Family)这一概念,它指的是位于不同的产品登记结构中,并且功能互相关联的产品系列,如下图:

  

  图上三个箭头所指就是三个功能湘湖关联的产品,它们位于三个不同的产品登记结构中的相同位置上,共同组成了一个产品族。抽象工厂就是要生成这样的产品族。而在这种产品族中,各产品之间有关联耦合,抽象工厂会将这种关联耦合设计成一个抽象类。抽象工厂模式符合GRASP的纯虚构模式,同事取得高内聚低耦合的效果。

  其UML类图如下:

  

  其中的类或对象之间的关系为:

  1. AbstractFactory(抽象工厂):声明生成抽象产品的方法。

  2. ConcreteFactory(具体工厂):执行生成抽象产品的方法,生成一个具体的产品。

  3. AbstractProduct(抽象产品):为一种产品声明接口。

  4. Product(具体产品):定义具体工厂生成的具体产品的对象,实现产品接口。

  5. Clint(客户):我们的应用程序,使用抽象产品和抽象工厂生成对象。

  典型应用的顺序图如下:

  

  抽象工厂负责创建不同的有联系的多个产品,不同的抽象工厂创建的产品不同,但产品之间的关系相同,抽象工厂是GRASP模式的纯虚构的表现。

  • 实例1——大陆生态系统

  大家都知道,动物世界中各大陆的动物是不一样的,各种动物可以分成两样,一种食草,一种食肉。食肉的动物吃食草动物。美洲狼属于食肉动物,野牛属于食草动物,美洲狼猎吃野牛;非洲的狮子属于食肉动物,角马属于食草动物,狮子猎吃角马。类的关系图如下:

  

  

代码
//抽象大陆工厂
abstract class ContinentFacctory
{
abstract public Herbivore CreateHerbivore();
abstract public Carnivore CreateCarnivore();
}
//非洲大陆,有角马、狮子
class AfricaFactory : ContinentFacctory
{
public override Herbivore CreateHerbivore()
{
return new Wildebeest();
}

public override Carnivore CreateCarnivore()
{
return new Lion();
}
}
//美洲大陆,有野牛、狼
class AmericaFactory : ContinentFacctory
{
public override Herbivore CreateHerbivore()
{
return new Bison();
}

public override Carnivore CreateCarnivore()
{
return new Wolf();
}
}

//食草动物
abstract class Herbivore { }
//食肉动物
abstract class Carnivore
{
abstract public void Eat(Herbivore h);
}
//角马
class Wildebeest : Herbivore { }
//狮子
class Lion : Carnivore
{
public override void Eat(Herbivore h)
{
Console.WriteLine(
this + " eats" + h);
}
}
//野牛
class Bison : Herbivore { }
//
class Wolf : Carnivore
{
public override void Eat(Herbivore h)
{
Console.WriteLine(
this + " eats" + h);
}
}

//动物世界
class AnimalWorld
{
private Herbivore herbivore;
private Carnivore carnivore;
//创建两种动物分类
public AnimalWorld(ContinentFacctory factory)
{
carnivore
= factory.CreateCarnivore();
herbivore
= factory.CreateHerbivore();
}
//运行食物链
public void RunFoodChain()
{
carnivore.Eat(herbivore);
}
}

//客户应用测试
class Client
{
[STAThread]
static void Main(string[] args)
{
//创造并运行非洲动物世界
ContinentFacctory africa = new AfricaFactory();
AnimalWorld world
= new AnimalWorld(africa);
world.RunFoodChain();

//创造兵运行美洲动物世界
ContinentFacctory america = new AmericaFactory();
world
= new AnimalWorld(america);
world.RunFoodChain();

Console.Read();
}
}

 

 

  • 实例2——电脑产品

  IBM,Dell都是著名的计算机生产厂家,他们采用的主办、硬盘及CPU。但配件间、主板与CPU一定要互相兼容例如下面例子中的微星MSIK7N2G配AMD的CPU;微星MSI865PE配Intel的CPU。类图如下:

  

  

代码
//定义CPU接口
public interface iCPU
{
string GetCPU();
}
//定义AMD类,实现CPU接口
public class AMD : iCPU
{
public string GetCPU()
{
return "Athlon XP 2800+";
}
}
//定义Intel类,实现CPU接口
public class Intel : iCPU
{
public string GetCPU()
{
return "奔腾4 3.2C";
}
}

//定义硬盘接口
public interface iHardDisc
{
string GetSize();
}
//定义Maxtor类,实现硬盘接口
public class Maxtor : iHardDisc
{
public string GetSize()
{
return "MaXLine Plus II 200G";
}
}
//定义WestDigit类,实现硬盘接口
public class WestDigit : iHardDisc
{
public string GetSize()
{
return "WD2500JD 250G";
}
}

//定义主板接口,包含参数为iCPU的公共方法Attach()
public interface iMainBoard
{
void Attach(iCPU cpu);
}
//主板微星MSI865PE,支持Intel的CPU
public class MSI865PE : iMainBoard
{
public void Attach(iCPU icpu)
{
if (icpu.GetType().Name.ToLower() == "intel")
Console.WriteLine(
"MSI865PE");
else
throw new Exception("主板MSI865PE只能配Intel的CPU");
}
}
//主板微星MSIK7N2G,支持AMD的CPU
public class MSIK7N2G : iMainBoard
{
public void Attach(iCPU icpu)
{
if (icpu.GetType().Name.ToLower() == "amd")
Console.WriteLine(
"MSIK7N2G");
else
throw new Exception("主板MSIK7N2G只能配AMD的CPU");
}
}

//定义抽象电脑工厂类
public abstract class ComputerFactory
{
protected iCPU icpu;
protected iHardDisc iHD;
protected iMainBoard iMB;
public void Show()
{
try
{
Console.WriteLine(
this.GetType().Name + "生产的电脑配置");
Console.WriteLine(
"CPU:" + icpu.GetCPU());
Console.WriteLine(
"HardDisk:" + iHD.GetSize());
Console.WriteLine(
"MainBoard:");
iMB.Attach(icpu);
}
catch( Exception e)
{
Console.Error.WriteLine(e.Message);
}
}
}
//抽象电脑工厂类派生类IBM,定义其返回的系列配件产品
public class IBM : ComputerFactory
{
public IBM()
{
icpu
= new Intel();
iHD
= new WestDigit();
iMB
= new MSI865PE();
}
}
//抽象电脑工厂类派生类DELL,定义其返回的系列配件产品
public class Dell : ComputerFactory
{
public Dell()
{
icpu
= new AMD();
iHD
= new Maxtor();
iMB
= new MSIK7N2G();
}
}

//客户应用测试
class Client
{
[STAThread]
static void Main(string[] args)
{
IBM ibm
= new IBM();
ibm.Show();
Dell dell
= new Dell();
dell.Show();
Console.Read();
}
}

 

 

  • 优势和缺陷

  抽象工厂模式的主要优点是隔离了具体类的生成,使得客户不需要知道什么被创建了。犹豫这种隔离,更换一个具体工厂就变得相对容易。所有的具体工厂都实现了抽象工厂中定义的那些公共接口,因此只需改变具体工厂的实例,就可以在某种程度上改变这个软件的系统的行为。另外,应用抽象工厂模式符合GRASP纯虚构的模式,可以实现高内聚低耦合的设计目的,因此抽象工厂模式得到了广泛应用。

  使用抽象工厂模式的最大好处是,当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。这对一些需要根据当前环境来决定其行为的软件系统来说,是非常使用的一种设计模式。

  抽象工厂模式的确定是,在添加新的产品对象时,难易扩展抽象工厂以便生产新种类的产品。这是因为AbstractFatory接口规定了所有可能被创建的产品集合,要支持新种类的产品就意味着要对该接口进行扩展,而这将涉及到对AbstractFatory及其所有子类的修改,显然有小小的不便,但不重要。

  • 应用情景

  下面的情景很适合应用抽象工厂模式:

  1. 系统需要屏蔽有关对象如何创建、如何组织和如何表示。

  2. 系统需要由关联的多个对象来构成。

  3. 有关联的多个对象需要一起应用并且它们的约束是强迫的(不可分离)。

  4. 你想提供一组对象而不显示他们的实现过程,只显示它们的接口。

posted on 2010-10-22 00:02  tLEE  阅读(1079)  评论(0编辑  收藏  举报

导航