1、C#设计模式,第3部分 构造型模式,第14章构造型模式介绍,创建型模式抽象了实例化过程。它们帮助一个系统独立于如何创建、组合和表示它的那些对象。一个类创建型模式使用继承改变被实例化的类,而一个对象创建型模式将实例化委托给另一个对象。随着系统演化得越来越依赖于对象复合而不是类继承,创建型模式变得更为重要。当这种情况发生时,重心从对一组固定行为的硬编码( h a r d - c o d i n g)转移为定义一个较小的基本行为集,这些行为可以被组合成任意数目的更复杂的行为。这样创建有特定行为的对象要求的不仅仅是实例化一个类。,在这些模式中有两个不断出现的主旋律。第一,它们都将关于该系统使用哪些具体
2、的类的信息封装起来。第二,它们隐藏了这些类的实例是如何被创建和放在一起的。整个系统关于这些对象所知道的是由抽象类所定义的接口。因此,创建型模式在什么被创建, 谁创建它,它是怎样被创建的,以及何时创建这些方面给予你很大的灵活性。它们允许你用结构和功能差别很大的“产品”对象配置一个系统。配置可以是静态的(即在编译时指定),也可以是动态的(在运行时)。,有时创建型模式是相互竞争的。例如,在有些情况下P r o t o t y p e或Abstract Factory用起来都很好。而在另外一些情况下它们是互补的: B u i l d e r可以使用其他模式去实现某个构件的创建。P r o t o t
3、y p e可以在它的实现中使用S i n g l e t o n。,例:一个电脑游戏创建一个迷宫,这个迷宫和游戏将随着各种模式不同而略有区别。有时这个游戏将仅仅是找到一个迷宫的出口;在这种情况下,游戏者可能仅能见到该迷宫的局部。有时迷宫包括一些要解决的问题和要战胜的危险,并且这些游戏可能会提供已经被探索过的那部分迷宫地图。,每一个房间有四面,我们使用C + +中的枚举类型D i r e c t i o n来指定房间的东南西北:enum Direction North, South, East, West;,类M a p S i t e是所有迷宫组件的公共抽象类。为简化例子, M a p S i
4、 t e仅定义了一个操作E n t e r,它的含义决定于你在进入什么。如果你进入一个房间,那么你的位置会发生改变。如果你试图进入一扇门,那么这两件事中就有一件会发生:如果门是开着的,你进入另一个房间。如果门是关着的,那么你就会碰壁。,enum Direction North, South, East, West;,创建型模式显示如何使得这个设计更灵活,但未必会更小。特别是,它们将便于修改定义一个迷宫构件的类。 假设你想在一个包含(所有的东西)施了魔法的迷宫的新游戏中重用一个已有的迷宫布局。施了魔法的迷宫游戏有新的构件,像D o o r N e e d i n g S p e l l,它是一扇
5、仅随着一个咒语才能被锁上和打开的门;以及E n c h a n t e d R o o m,一个可以有不寻常东西的房间,比如魔法钥匙或是咒语。你怎样才能较容易的改变C r e a t e M a z e以让它用这些新类型的对象创建迷宫呢?这种情况下,改变的最大障碍是对被实例化的类进行硬编码。创建型模式提供了多种不同方法从实例化它们的代码中除去对这些具体类的显式引。, 如果C r e a t e M a z e调用虚函数而不是构造器来创建它需要的房间、墙壁和门,那么你可以创建一个M a z e G a m e的子类并重定义这些虚函数,从而改变被例化的类。这一方法是Factory Method模式
6、的一个例子。 如果传递一个对象给C r e a t e M a z e作参数来创建房间、墙壁和门,那么你可以传递不同的参数来改变房间、墙壁和门的类。这是Abstract Factory模式的一个例子。 如果传递一个对象给C r e a t e M a z e,这个对象可以在它所建造的迷宫中使用增加房间、墙壁和门的操作,来全面创建一个新的迷宫,那么你可以使用继承来改变迷宫的一些部分或该迷宫被建造的方式。这是B u i l d e r模式的一个例子。 如果C r e a t e M a z e由多种原型的房间、墙壁和门对象参数化,它拷贝并将这些对象增加到迷宫中,那么你可以用不同的对象替换这些原型对
7、象以改变迷宫的构成。这是P r o t o t y p e模式的一个例子。 剩下的创建型模式, S i n g l e t o n,可以保证每个游戏中仅有一个迷宫而且所有的游戏对象都可以迅速访问它不需要求助于全局变量或函数。S i n g l e t o n也使得迷宫易于扩展或替换,且不需变动已有的代码。,第15章 BUILDER(生成器) 对象创建型模式,1. 意图 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。 2. 动机 一个RT F(Rich Text Format)文档交换格式的阅读器应能将RT F转换为多种正文格式。该阅读器可以将RT F文档转换成普通A
8、 S C I I文本或转换成一个能以交互方式编辑的正文窗口组件。但问题在于可能转换的数目是无限的。因此要能够很容易实现新的转换的增加,同时却不改变RT F阅读器。,一个解决办法是用一个可以将RT F转换成另一种正文表示的Te x t C o n v e r t e r对象配置这个RT F R e a d e r类。当RT F R e a d e r对RT F文档进行语法分析时,它使用Te x t C o n v e r t e r去做转换。无论何时RT F R e a d e r识别了一个RT F标记(或是普通正文或是一个RT F控制字),它都发送一个请求给Te x t C o n v e r
9、 t e r去转换这个标记。Te x t C o n v e r t e r对象负责进行数据转换以及用特定格式表示该标记,如下图所示。,Te x t C o n v e r t的子类对不同转换和不同格式进行特殊处理。例如,一个A S C I I C o n v e r t e r只负责转换普通文本,而忽略其他转换请求。另一方面,一个Te X C o n v e r t e r将会为实现对所有请求的操作,以便生成一个获取正文中所有风格信息的T E X表示。一个Te x t Wi d g e t C o n v e r t e r将生成一个复杂的用户界面对象以便用户浏览和编辑正文。 每种转换器类将
10、创建和装配一个复杂对象的机制隐含在抽象接口的后面。转换器独立于阅读器,阅读器负责对一个RT F文档进行语法分析。 B u i l d e r模式描述了所有这些关系。每一个转换器类在该模式中被称为生成器( b u i l d e r),而阅读器则称为导向器( d i r e c t o r)。在上面的例子中, B u i l d e r模式将分析文本格式的算法(即RT F文档的语法分析程序)与描述怎样创建和表示一个转换后格式的算法分离开来。这使我们可以重用RT F R e a d e r的语法分析算法,根据RT F文档创建不同的正文表示仅需使用不同的Te x t C o n v e r t e
11、r的子类配置该RT F R e a d e r即可。,3. 适用性 在以下情况使用B u i l d e r模式 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。 当构造过程必须允许被构造的对象有不同的表示时。,4. 结构 此模式结构如图所示。,5. 参与者 B u i l d e r(Te x t C o n v e r t e r) 为创建一个P r o d u c t对象的各个部件指定抽象接口。 C o n c r e t e B u i l d e r(A S C I I C o n v e r t e r、Te X C o n v e r t e r、Te x t
12、 Wi d g e t C o n v e r t e r) 实现B u i l d e r的接口以构造和装配该产品的各个部件。 定义并明确它所创建的表示。 提供一个检索产品的接口(例如, G e t A S C I I Te x t和G e t Te x t Wi d g e t)。 Director(RT F R e a d e r) 构造一个使用B u i l d e r接口的对象。 P r o d u c t(A S C I I Te x t、Te X Te x t、Te x t Wi d g e t) 表示被构造的复杂对象。C o n c r e t e B u i l d e r创
13、建该产品的内部表示并定义它的装配过程。 包含定义组成部件的类,包括将这些部件装配成最终产品的接口。,6. 协作 客户创建D i r e c t o r对象,并用它所想要的B u i l d e r对象进行配置。 一旦产品部件被生成,导向器就会通知生成器。 生成器处理导向器的请求,并将部件添加到该产品中。 客户从生成器中检索产品。 下面的交互图说明了B u i l d e r和D i r e c t o r是如何与一个客户协作的。,7. 效果 这里是B u i l d e r模式的主要效果:,1 ) 它使你可以改变一个产品的内部表示 2) 它将构造代码和表示代码分开 3 ) 它使你可对构造过程进
14、行更精细的控制,实现:,1) 装配和构造接口 生成器逐步的构造它们的产品。因此B u i l d e r类接口必须足够普遍,以便为各种类型的具体生成器构造产品。 2) 为什么产品没有抽象类通常情况下,由具体生成器生成的产品,它们的表示相差是如此之大以至于给不同的产品以公共父类没有太大意思。 3 ) 在B u i l d e r中却省的方法为空C + +中,生成方法故意不声明为纯虚成员函数,而是把它们定义为空方法,这使客户只重定义他们所感兴趣的操作。,8. 已知应用 RT F转换器应用来自E T + + W G M 8 8 。它的正文生成模块使用一个生成器处理以RT F格式存储的正文。 生成器在
15、S m a l l t a l k - 8 0 P a r 9 0 中是一个通用的模式: 编译子系统中的P a r s e r类是一个D i r e c t o r,它以一个P r o g r a m N o d e B u i l d e r对象作为参数。 每当P a r s e r对象识别出一个语法结构时,它就通知它的P r o g r a m N o d e B u i l d e r对象。当这个语法分析器做完时,它向该生成器请求它生成的语法分析树并将语法分析树返回给客户。, C l a s s B u i l d e r是一个生成器, C l a s s使用它为自己创建子类。在这个例子
16、中,一个C l a s s既是D i r e c t o r也是P r o d u c t。 B y t e C o d e S t r e a m 是一个生成器,它将一个被编译了的方法创建为字节数组。 B y t e C o d e S t r e a m不是B u i l d e r模式的标准使用,因为它生成的复杂对象被编码为一个字节数组,而不是正常的S m a l l t a l k对象。但B y t e C o d e S t r e a m的接口是一个典型的生成器,而且将很容易用一个将程序表示为复合对象的不同的类来替换B y t e C o d e S t r e a m。 自适应通
17、讯环境( Adaptive Communications Environment )中的服务配置者( S e r v i c eC o n f i g u r a t o r)框架使用生成器来构造运行时刻动态连接到服务器的网络服务构件 S S 9 4 。这些构件使用一个被L A L R(1)语法分析器进行语法分析的配置语言来描述。这个语法分析器的语义动作对将信息加载给服务构件的生成器进行操作。在这个例子中,语法分析器就是D i r e c t o r。,9. 相关模式 Abstract Factory 与B u i l d e r相似,因为它也可以创建复杂对象。主要的区别是B u i l d
18、e r模式着重于一步步构造一个复杂对象。而Abstract Factory着重于多个系列的产品对象(简单的或是复杂的)。B u i l d e r在最后的一步返回产品,而对于Abstract Factory来说,产品是立即返回的。 C o m p o s i t e通常是用B u i l d e r生成的。,第16章 FACTORY METHOD (工厂方法),1. 意图 定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使一个类的实例化延迟到其子类。 2. 别名 虚构造器( Virtual Constructor),3. 动机 框架使用抽象类定义和维护对象之间
19、的关系。这些对象的创建通常也由框架负责。 考虑这样一个应用框架,它可以向用户显示多个文档。在这个框架中,两个主要的抽象是类A p p l i c a t i o n和D o c u m e n t。这两个类都是抽象的,客户必须通过它们的子类来做与具体应用相关的实现。例如,为创建一个绘图应用,我们定义类D r a w i n g A p p l i c a t i o n和D r a w i n g D o c u m e n t。A p p l i c a t i o n类负责管理D o c u m e n t并根据需要创建它们例如,当用户从菜单中选择O p e n或N e w的时候。,因为被
20、实例化的特定D o c u m e n t子类是与特定应用相关的,所以A p p l i c a t i o n类不可能预测到哪个D o c u m e n t子类将被实例化A p p l i c a t i o n类仅知道一个新的文档何时应被创建,而不知道哪一种D o c u m e n t将被创建。这就产生了一个尴尬的局面:框架必须实例化类,但是它只知道不能被实例化的抽象类。,A p p l i c a t i o n的子类重定义A p p l i c a t i o n的抽象操作C r e a t e D o c u m e n t以返回适当的D o c u m e n t子类对象。一旦
21、一个A p p l i c a t i o n子类实例化以后,它就可以实例化与应用相关的文档,而无需知道这些文档的类。我们称C r e a t e D o c u m e n t是一个工厂方法( f a c t o r y m e t h o d),因为它负责“生产”一个对象。,Factory Method模式提供了一个解决办案。它封装了哪一个D o c u m e n t子类将被创建的信息并将这些信息从该框架中分离出来,如下页上图所示。,6. 参与者 P r o d u c t( D o c u m e n t ) 定义工厂方法所创建的对象的接口。 C o n c r e t e P r o
22、 d u c t(M y D o c u m e n t) 实现P r o d u c t接口。 C r e a t o r(A p p l i c a t i o n) 声明工厂方法,该方法返回一个P r o d u c t类型的对象。C r e a t o r也可以定义一个工厂方法的缺省实现,它返回一个缺省的C o n c r e t e P r o d u c t对象。 可以调用工厂方法以创建一个P r o d u c t对象。 C o n c r e t e C r e a t o r(M y A p p l i c a t i o n) 重定义工厂方法以返回一个C o n c r e
23、 t e P r o d u c t实例。 7. 协作 Creator依赖于它的子类来定义工厂方法,所以它返回一个适当的C o n c r e t e P r o d u c t实例。,8.效果 工厂方法不再将与特定应用有关的类绑定到你的代码中。代码仅处理P r o d u c t接口;因此它可以与用户定义的任何C o n c r e t e P r o d u c t类一起使用。 工厂方法的一个潜在缺点在于客户可能仅仅为了创建一个特定的C o n c r e t e P r o d u c t对象,就不得不创建C r e a t o r的子类。当C r e a t o r子类不必需时,客户现
24、在必然要处理类演化的其他方面;但是当客户无论如何必须创建C r e a t o r的子类时,创建子类也是可行的。,下面是Factory Method模式的另外两种效果: 1 ) 为子类提供挂钩( h o o k) 用工厂方法在一个类的内部创建对象通常比直接创建对象更灵活。Factory Method给子类一个挂钩以提供对象的扩展版本。 2) 连接平行的类层次迄今为止,在我们所考虑的例子中,工厂方法并不往往只是被C r e a t o r调用,客户可以找到一些有用的工厂方法,尤其在平行类层次的情况下。,当一个类将它的一些职责委托给一个独立的类的时候,就产生了平行类层次。考虑可以被交互操纵的图形;
25、也就是说,它们可以用鼠标进行伸展、移动,或者旋转。实现这样一些交互并不总是那么容易,它通常需要存储和更新在给定时刻记录操纵状态的信息,这个状态仅仅在操纵时需要。因此它不需要被保存在图形对象中。此外,当用户操纵图形时,不同的图形有不同的行为。例如,将直线图形拉长可能会产生一个端点被移动的效果,而伸展正文图形则可能会改变行距。,有了这些限制,最好使用一个独立的M a n i p u l a t o r对象实现交互并保存所需要的任何与特定操纵相关的状态。不同的图形将使用不同的M a n i p u l a t o r子类来处理特定的交互。得到的M a n i p u l a t o r类层次与F i
26、 g u r e类层次是平行(至少部分平行),如下图所示。,9. 实现 当应用Factory Method模式时要考虑下面一些问题: 1 ) 主要有两种不同的情况Factory Method模式主要有两种不同的情况: 1)第一种情况是, C r e a t o r类是一个抽象类并且不提供它所声明的工厂方法的实现。 2)第二种情况是,C r e a t o r是一个具体的类而且为工厂方法提供一个缺省的实现。也有可能有一个定义了缺省实现的抽象类,但这不太常见。,第一种情况需要子类来定义实现,因为没有合理的缺省实现。它避免了不得不实例化不可预见类的问题。 在第二种情况中,具体的C r e a t o
27、 r主要因为灵活性才使用工厂方法。它所遵循的准则是,“用一个独立的操作创建对象,这样子类才能重定义它们的创建方式。”这条准则保证了子类的设计者能够在必要的时候改变父类所实例化的对象的类。,2 ) 参数化工厂方法该模式的另一种情况使得工厂方法可以创建多种产品。工厂方法采用一个标识要被创建的对象种类的参数。工厂方法创建的所有对象将共享P r o d u c t接口。在D o c u m e n t的例子中,A p p l i c a t i o n可能支持不同种类的D o c u m e n t。你给C r e a t e D o c u m e n t传递一个外部参数来指定将要创建的文档的种类。
28、,重定义一个参数化的工厂方法使你可以简单而有选择性的扩展或改变一个C r e a t o r生产的产品。你可以为新产品引入新的标识符,或可以将已有的标识符与不同的产品相关联。 例如,子类M y C r e a t o r可以交换M y P r o d u c t 和Yo u r P r o d u c t并且支持一个新的子类,3) 特定语言的变化和问题不同的语言有助于产生其他一些有趣的变化和警告( c a v e a t)。 C + +中的工厂方法都是虚函数并且常常是纯虚函数。一定要注意在C r e a t o r的构造器中不要调用工厂方法在C o n c r e t e C r e a t
29、o r中该工厂方法还不可用。,4 )使用模板以避免创建子类正如我们已经提及的,工厂方法另一个潜在的问题是它们可能仅为了创建适当的P r o d u c t对象而迫使你创建C r e a t o r子类。 在C + +中另一个解决方法是提供C r e a t o r的一个模板子类,它使用P r o d u c t类作为模板参数:,使用这个模板,客户仅提供产品类而不需要创建C r e a t o r的子类。,5 ) 命名约定使用命名约定是一个好习惯,它可以清楚地说明你正在使用工厂方法。例如,M a c i n t o s h的应用框架MacApp App89总是声明那些定义为工厂方法的抽象操作为C
30、 l a s s *DoMakeClass( ),此处C l a s s是P r o d u c t类。,10. 代码示例 函数C r e a t e M a z e(第3章)建造并返回一个迷宫。这个函数存在的一个问题是它对迷宫、房间、门和墙壁的类进行了硬编码。我们将引入工厂方法以使子类可以选择这些构件。首先我们将在M a z e G a m e中定义工厂方法以创建迷宫、房间、墙壁和门对象:,每一个工厂方法返回一个给定类型的迷宫构件。M a z e G a m e提供一些缺省的实现,它们返回最简单的迷宫、房间、墙壁和门。现在我们 以用这些工厂方法重写C r e a t e M a z e:,不
31、同的游戏可以创建M a z e G a m e的子类以特别指明一些迷宫的部件。M a z e G a m e子类可以重定义一些或所有的工厂方法以指定产品中的变化。例如,一个B o m b e d M a z e G a m e可以重定义产品R o o m和Wa l l以返回爆炸后的变体:,一个E n c h a n t e d M a z e G a m e变体可以像这样定义:,11. 已知应用 工厂方法主要用于工具包和框架中。前面的文档例子是M a c A p p和E T + + W G M 8 8 中的一个典型应用。操纵器的例子来自U n i d r a w。 Smalltalk-80 M
32、odel/Vi e w / C o n t r o l l e r框架中的类视图( Class Vi e w)有一个创建控制器的方法d e f a u l t C o n t r o l l e r,它有点类似于一个工厂方法 P a r 9 0 。但是Vi e w的子类通过定义d e f a u l t C o n t r o l l e r C l a s s 来指定它们默认的控制器的类。d e f a u l t C o n t r o l l e r C l a s s返回d e f a u l t C o n t r o l l e r所创建实例的类,因此它才是真正的工厂方法,即子类应
33、该重定义它。 S m a l l t a l k - 8 0中一个更为深奥的例子是由B e h a v i o r(用来表示类的所有对象的超类)定义的工厂方法p a r s e r C l a s s。这使得一个类可以对它的源代码使用一个定制的语法分析器。,12. 相关模式 Abstract Factory(3 . 1)经常用工厂方法来实现。Abstract Factory模式中动机一节的例子也对Factory Method进行了说明。 工厂方法通常在Template Methods(5 . 1 0)中被调用。在上面的文档例子中,N e w D o c u m e n t就是一个模板方法。 P
34、 r o t o t y p e s(3 . 4)不需要创建C r e a t o r的子类。但是,它们通常要求一个针对P r o d u c t类的I n i t i a l i z e操作。C r e a t o r使用I n i t i a l i z e来初始化对象。而Factory Method不需要这样的操作。,第 17章 ABSTRACT FACTORY (抽象工厂)对象创建型模式,1. 意图 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。 2. 别名 K i t 3. 动机考虑一个支持多种视感( l o o k - a n d - f e e l)标准的用
35、户界面工具包,例如M o t i f和Presentation Manager。不同的视感风格为诸如滚动条、窗口和按钮等用户界面“窗口组件”定义不同的外观和行为。为保证视感风格标准间的可移植性,一个应用不应该为一个特定的视感外观硬编码它的窗口组件。在整个应用中实例化特定视感风格的窗口组件类将使得以后很难改变视感风格。,为解决这一问题我们可以定义一个抽象的Wi d g e t F a c t o r y类,这个类声明了一个用来创建每一类基本窗口组件的接口。每一类窗口组件都有一个抽象类,而具体子类则实现了窗口组件的特定视感风格。对于每一个抽象窗口组件类, Wi d g e t F a c t o
36、r y接口都有一个返回新窗口组件对象的操作。客户调用这些操作以获得窗口组件实例,但客户并不知道他们正在使用的是哪些具体类。这样客户就不依赖于一般的视感风格,如下页图所示。,每一种视感标准都对应于一个具体的Wi d g e t F a c t o r y子类。每一子类实现那些用于创建合适视感风格的窗口组件的操作。例如, M o t i f Wi d g e t F a c t o r y的C r e a t e S c r o l l B a r操作实例化并返回一个M o t i f滚动条,而相应的P M Wi d g e t F a c t o r y操作返回一个Presentation Ma
37、nager的滚动条。客户仅通过Wi d g e t F a c t o r y接口创建窗口组件,他们并不知道哪些类实现了特定视感风格的窗口组件。换言之,客户仅与抽象类定义的接口交互,而不使用特定的具体类的接口。 Wi d g e t F a c t o r y也增强了具体窗口组件类之间依赖关系。一个M o t i f的滚动条应该与M o t i f按钮、M o t i f正文编辑器一起使用,这一约束条件作为使用M o t i f Wi d g e t F a c t o r y的结果被自动加上。,4. 适用性 在以下情况可以使用Abstract Factory模式 一个系统要独立于它的产品的创
38、建、组合和表示时。 一个系统要由多个产品系列中的一个来配置时。 当你要强调一系列相关的产品对象的设计以便进行联合使用时。 当你提供一个产品类库,而只想显示它们的接口而不是实现时。,5. 结构 此模式的结构如下图所示。,6. 参与者 A b s t r a c t F a c t o r y ( Wi d g e t F a c t o r y ) 声明一个创建抽象产品对象的操作接口。 C o n c r e t e F a c t o r y ( M o t i f Wi d g e t F a c t o r y,P M Wi d g e t F a c t o r y ) 实现创建具体产品
39、对象的操作。 A b s t r a c t P r o d u c t ( Wi n d o w s,S c r o l l B a r ) 为一类产品对象声明一个接口。 C o n c r e t e P r o d u c t ( M o t i f Wi n d o w,M o t i f S c r o l l B a r ) 定义一个将被相应的具体工厂创建的产品对象。 实现A b s t r a c t P r o d u c t接口。 C l i e n t 仅使用由A b s t r a c t F a c t o r y和A b s t r a c t P r o d u c
40、 t类声明的接口。,7. 协作 通常在运行时刻创建一个C o n c r e t e F a c t r o y类的实例。这一具体的工厂创建具有特定实现的产品对象。为创建不同的产品对象,客户应使用不同的具体工厂。 AbstractFactory将产品对象的创建延迟到它的C o n c r e t e F a c t o r y子类。,8. 效果 A b s t r a c t F a c t o r y模式有下面的一些优点和缺点: 1) 它分离了具体的类 Abstract Factory模式帮助你控制一个应用创建的对象的类。因为一个工厂封装创建产品对象的责任和过程,它将客户与类的实现分离。客户
41、通过它们的抽象接口操纵实例。产品的类名也在具体工厂的实现中被分离;它们不出现在客户代码中。 2) 它使得易于交换产品系列 一个具体工厂类在一个应用中仅出现一次即在它初始化的时候。这使得改变一个应用的具体工厂变得很容易。它只需改变具体的工厂即可使用不同的产品配置,这是因为一个抽象工厂创建了一个完整的产品系列,所以整个产品系列会立刻改变。在我们的用户界面的例子中,我们仅需转换到相应的工厂对象并重新创建接口,就可实现从M o t i f窗口组件转换为Presentation Manager窗口组件。,3) 它有利于产品的一致性当一个系列中的产品对象被设计成一起工作时,一个应用一次只能使用同一个系列中
42、的对象,这一点很重要。而A b s t r a c t F a c t o r y很容易实现这一点。 4) 难以支持新种类的产品难以扩展抽象工厂以生产新种类的产品。这是因为A b s t r a c t F a c t o r y接口确定了可以被创建的产品集合。支持新种类的产品就需要扩展该工厂接口,这将涉及A b s t r a c t F a c t o r y类及其所有子类的改变。我们会在实现一节讨论这个问题的一个解决办法。,9. 已知应用 I n t e r Vi e w使用“K i t”后缀 L i n 9 2 来表示A b s t r a c t F a c t o r y类。它定义
43、Wi d g e t K i t和D i a l o g K i t抽象工厂来生成与特定视感风格相关的用户界面对象。I n t e r Vi e w还包括一个L a y o u t K i t,它根据所需要的布局生成不同的组成( c o m p o s i t i o n)对象。例如,一个概念上是水平的布局根据文档的定位(画像或是风景)可能需要不同的组成对象。E T + + W G M 8 8 使用Abstract Factory模式以达到在不同窗口系统(例如, X Wi n d o w s和S u n Vi e w)间的可移植性。Wi n d o w S y s t e m抽象基类定义一些接口,来创建表示窗口系统资源的对象(例如M a k e Wi n d o w、M a k e F o n t、M a k e C o l o r)。具体的子类为某个特定的窗口系统实现这些接口。运行时刻, E T + +创建一个具体Wi n d o w S y s t e m子类的实例,以创建具体的系统资源对象。 10. 相关模式 A b s t r a c t F a c t o r y类通常用工厂方法( Factory Method (3 . 3)实现,但它们也可以用P r o t o t y p e实现。 一个具体的工厂通常是一个单件( S i n g l e t o n(3 . 5)。,