代码改变世界

大家一起学面向对象设计模式系列Chapter 03 抽象工厂(Abstract Factory)

2009-03-16 17:43  GUO Xingwang  阅读(2323)  评论(9编辑  收藏  举报

     现在我们正式进入GoF23种设计模式中的创建型模式的讲解中来,创建型模式主要解决对象如何创建的问题,提倡创建对象的责任和使用对象的责任分离,以达到更好对创建对象的控制的目的,创建型模式主要包括抽象工厂(Abstract Factory),建造者(Builder),工厂方法(Factory Method),原型(Prototype),单子(Singleton)。这篇文章主要分为两大部分内容,在第一部分中我将介绍抽象工厂模式的原型,包括抽象工厂的意图,可以解决的问题,原型代码和UML等,再结合一个生活中的小例子进行原型的说明。第二部分我会结合实际项目来讲述一下抽象工厂模式是如何应用的。最后我会对抽象工厂模式进行一个小结。

     工厂模式的几种形态

     工厂模式专门负责将大量有共同接口的类实例化。工厂模式可以动态决定将哪一个类实例化,不必事先知道每次要实例化哪一个类。工厂模式有以下几种形态:

简单工厂(Simple Factory)模式:又称静态工厂方法模式(Static Factory Method Pattern)。主要是工厂中提供一个静态的方法用来根据不同的参数创建不同的抽象产品的具体实例,一般在IoC中应用比较多,例如通过反射机制和简单工厂模式可以解决依赖注入的问题。简单工厂模式不属于GoF23种设计模式,这里也就不再作过多的分析。感兴趣的园友可以找找相关资料。

工厂方法(Factory Method)模式:又称多态性工厂(Polymorphic Factory)模式或虚拟构造子(Virtual Constructor)模式。这个模式属于GoF23种设计模式之一,在后面的文章中会做详细的介绍。

抽象工厂(Abstract Factory)模式:又称工具箱(Kit或Toolkit)模式。这是本文的重点。

     抽象工厂模式的原型

     描述:

     假设一个子系统需要一些产品对象,而这些产品对象又属于一个以上的产品等级结构。那么为了将消费这些产品的责任和创建这些产品对象的责任分割开来,可以引进抽象工厂模式。这样的话,消费产品的一方不需要直接参与产品的创建工作,而只需要向一个公用的工厂接口请求所需要的产品。

      意图:

     抽象工厂模式可以向客户端(Client指代码模式的使用者,后文类同)提供一个接口,使得客户端在不必指定产品的具体类型的情况下,创建多个产品族(Product Family指位于不同产品等级中,功能相关联的产品的集合)中的产品对象。

     模式原型UML:

 

     

     抽象工厂涉及到以下角色:
     抽象工厂(AbstractFactory )角色:声明一个操作集合的接口以创建抽象产品族。
     具体工厂(ConcreteFactory)角色:实现创建具体产品族的抽象工厂的实现。
     抽象产品(AbstractProduct )角色:声明一个产品的接口。
     具体产品(Product)角色:定义了一个被具体工厂创建的产品对象,实现了抽象工厂接口。
     客户端(Client)角色:使用抽象工厂和抽象产品的类。

      模式原型代码:

Abstract Factory pattern code in C#

输出结果为:

ProductB1 interacts with ProductA1
ProductB2 interacts with ProductA2

     生活中的实例:

     这个生活中的实例代码演示了一个电脑游戏,在游戏中建立不同的动物世界会使用不同的工厂。虽然创建动物的大陆工厂是不同的,但是动物之间的相互关系保持不变。

Real world code using Abstract Factory in C#

输出的结果为:

Lion eats Wildebeest
Wolf eats Bison
 

     什么情况下使用抽象工厂:

文献【GOF95】指出,在以下情况下应当考虑使用抽象工厂模式:
1.一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有形态的工厂模式都是重要的。
2、这个系统的产品有多于一个产品族,而系统只消费其中某一个族的产品(上面这一条叫做抽象工厂模式的原始用意。)
3、同属于同一个产品族的产品是在一起使用的,这一约束必须在系统的设计中体现出来。
4、系统提供一个产品类的库,所有的产品以同样的接口实现,从而使客户端不依赖于实现。

     实际项目举例

     现在需要创建分属于不同操作系统的视窗构件。比如命令按钮(Button)与文本框(Text)等都是视窗构件,在UNIX系统的视窗环境和Windows操作系统的视窗环境中,这两个构件有不同的本地体现,它们的细节也有所不同。在每一个操作系统中,都有一个视窗构件组成构件家族。在这里就是Button和Text组成的产品族。而每一个视窗构件都构成自己的等级结构,由一个抽象角色给出抽象的功能描述,而由具体子类给出不同操作系统的具体实现,如下图所示。

     可以发现在上面的产品类图中,有两个产品的等级结构,分别是Button等级结构和Text等级结构、同时有两个产品族,也就是UNIX产品族和Windows产品族。UNIX产品族由UnixButton和UnixText产品组成;而Windows产品族由WinButton和WinText产品构成。

     系统对产品对象的创建需求由一个工厂的等级结构满足,其中有两个具体工厂角色,即UnixFactory和WinFactory。UnixFactory对象负责创建Unix产品族中的产品,而WinFactory对象负责创建Windows产品族中的产品。这就是抽象工厂模式的应用,抽象工厂模式的解决方案如下图所示。

     显然,一个系统只能够在某一个操作系统的视窗环境下运行,而不能够同时在不同的操作系统上运行。所以,系统实际上只能消费属于同一个产品族的产品。这个案例实际上也正是抽象工厂模式的起源。实现的代码如下。

 

Project code using Abstract Factory in C#

 输出结果为:

UnixText interact with UnixButton
WinText interact with WinButton

     小结

     抽象工厂模式是一个在实际项目中应用比较多的设计模式之一,抽象工厂模式面对的问题是多个产品等级结构的系统设计,运用抽象工厂模式的关键在于如果把创建产品的职责交给工厂去完成,希望大家在把握住工厂模式原型的基础上尽量的考虑到应用,形成一种思维上的定势。

      Welcome to share your idea,thank you!欢迎分享您的想法,谢谢!

      大家一起学面向对象设计模式系列 索引贴