您好,欢迎访问三七文档
《Java与模式》作者阎宏博士电子工业出版社出版第14章抽象工厂(AbstractFactory)模式在阅读本章之前,请首先阅读本书的“简单工厂(SimpleFactory)模式”以及“工厂方法(FactoryMethod)模式”两章。14.1引言抽象工厂模式的用意抽象工厂模式是所有形态的工厂模式中最为抽象和最具一般性的一种形态。抽象工厂模式的简略类图如下所示。左边的等级结构代表工厂等级结构,右边的两个等级结构分别代表两个不同的产品的等级结构。抽象工厂模式可以向客户端提供一个接口,使得客户端在不必指定产品的具体类型的情况下,创建多个产品族中的产品对象。这就是抽象工厂模式的用意。这是什么意思?相信很多读者会有这样的问题。为了说明抽象工厂模式的用意,不妨把它分成三段理解。Java与模式·194·第一段一个系统需要消费多个抽象产品角色,这些抽象产品角色可以用Java接口或者抽象Java类实现。读过本书的“工厂方法(FactoryMethod)模式”一章的读者可能会建议,既然客户端需要这些抽象产品角色的实例,为什么不使用一个工厂类负责创建这些角色的实例呢?工厂类负责创建抽象产品的实例描述如下图所示。但是,正如上面所指出的,这些抽象产品角色是由Java接口或者抽象Java类实现的,而一个Java接口或者抽象Java类是不能实例化的。也就是说,上面的设计是不能成立的。第二段那么怎么满足系统的需求呢?根据里氏代换原则,任何接收父类型的地方,都应当能够接收子类型。因此,实际上系统所需要的,仅仅是类型与这些抽象产品角色相同的一些实例,而不是这些抽象产品的实例。换言之,也就是这些抽象产品的具体子类的实例。工厂类负责创建抽象产品的具体子类的实例如下图所示。这就是抽象工厂模式用意的基本含义。第三段那么接下来的一个问题就是,如果每个抽象产品都有多于一个的具体子类的话,工厂角色怎么知道实例化哪一个子类呢?比如下面的类图中就给出了两个抽象产品,而每一个抽象产品都有两个具体产品。抽象工厂模式提供两个具体工厂角色,分别对应于这两个具体产品角色。每一个具体工厂角色仅负责某一个具体产品角色的实例化。每一个具体工厂类负责创建抽象产品的某第14章抽象工厂(AbstractFactory)模式·195·一个具体子类的实例如下图所示。涂有阴影的两个具体产品属于同一个产品族,关于产品族的概念,请见后面的讲解。理解了这三个步骤,就不难理解“抽象工厂”这个名字的来源了。“抽象”来自“抽象产品角色”,而“抽象工厂”就是抽象产品角色的工厂。14.2问题每一个模式都是针对一定问题的解决方案。正如前面所提到的,抽象工厂模式面对的问题是多个产品等级结构的系统设计。下面就从所面对的问题开始,将抽象工厂模式引进到系统设计中。多个产品等级结构抽象工厂模式与工厂方法模式的最大区别就在于,工厂方法模式针对的是一个产品等级结构;而抽象工厂模式则需要面对多个产品等级结构。下图给出了一个产品等级结构。下图则给出了多个相平行的产品等级结构的例子。Java与模式·196·产品族为了方便引进抽象工厂模式,特地引进一个新的概念:产品族(ProductFamily)。所谓产品族,是指位于不同产品等级结构中,功能相关联的产品组成的家族。比如在下图中,箭头所指就是三个功能相关联的产品,它们位于三个不同的等级结构中的相同位置上,组成一个产品族。显然,每一个产品族中含有产品的数目,与产品等级结构的数目是相等的。产品的等级结构和产品族将产品按照不同方向划分,形成一个二维的坐标系,如下图所示。第14章抽象工厂(AbstractFactory)模式·197·在坐标图中有四个产品族,分布于三个产品等级结构中。在上面的坐标图中,横轴表示产品等级结构,纵轴表示产品族。可以看出,图中一共有四个产品族,分布于三个不同的产品等级结构中。只要指明一个产品所处的产品族以及它所属的等级结构,就可以惟一地确定这个产品。这样的坐标图,叫做相图。在一个相图中,坐标轴代表抽象的自由度,相图中两个坐标点之间的绝对距离并没有意义,有意义的是点与点的相对位置。引进抽象工厂模式上面所给出的三个不同的等级结构具有平行的结构。因此,如果采用工厂方法模式,就势必要使用三个独立的工厂等级结构来对付这三个产品等级结构。由于这三个产品等级结构的相似性,会导致三个平行的工厂等级结构。随着产品等级结构的数目增加,工厂方法模式所给出的工厂等级结构的数目也会随之增加。那么,是否可以使用同一个工厂等级结构来对付这些相同或者极为相似的产品等级结构呢?当然是可以的,而这就是抽象工厂模式的好处。同一个工厂等级结构负责三个不同产品等级结构中的产品对象的创建,如下图所示,图中的虚线代表创建关系。可以看出,一个工厂等级结构可以创建出分属于不同产品等级结构的一个产品族中的所有对象;显然,这时候抽象工厂模式比工厂方法模式更有效率。Java与模式·198·应当指出的是,虽然大多数的文献都以一个含有两个层次(抽象和具体层次)的产品族作为讲解的例子,但在真实的系统中,产品族往往具有复杂的等级结构,就如同上面的图中所描述的一样,可以具有多于一个的抽象产品和很多的具体产品。如果使用相图来描述的话,就如下面的类图所示。在上面的相图中加入了具体工厂角色。可以看出,对应于每一个产品族都有一个具体工厂。而每一个具体工厂负责创建属于同一个产品族、但是分属于不同等级结构的产品。14.3抽象工厂模式的结构抽象工厂模式[GOF95]是对象的创建模式,它是工厂方法模式的进一步推广。假设一个子系统需要一些产品对象,而这些产品又属于一个以上的产品等级结构。那么为了将消费这些产品对象的责任和创建这些产品对象的责任分割开来,可以引进抽象工厂模式。这样的话,消费产品的一方不需要直接参与产品的创建工作,而只需要向一个公用的工厂接口请求所需要的产品。下面就以一个示意性的系统为例,说明这个模式的结构。产品对象的创建问题通过使用抽象工厂模式,可以处理具有相同(或者相似)等级结构的多个产品族中的产品对象创建问题。比如下面就是两个具有相同等级结构的产品族A和产品等级结构B的结构图。第14章抽象工厂(AbstractFactory)模式·199·如果使用相图描述的话,会看到在相图上出现两个等级结构A和B,以及两个产品族1和2。如下图所示。在上面的相图中,每一个坐标点都代表一个具体产品角色。可以看出,坐标点(A,1),(A,2),(B,1)和(B,2)分别对应于具体产品角色ProductA1,ProductA2,ProductB1,ProductB2等。就像本章前面所谈到的一样,如果使用工厂方法模式处理的话,就必须要有两个独立的工厂族。由于这两个产品族的等级结构相同,因此,使用同一个工厂族也可以处理这两个产品族的创建问题。后者就是抽象工厂模式,这样根据产品角色的结构图,就不难给出工厂角色的结构设计图,如下图所示。由于每个具体工厂角色都需要负责两个不同等级结构的产品对象的创建,因此每个工厂角色都需要提供两个工厂方法,分别用于创建两个等级结构的产品。既然每个具体工厂角色都需要实现这两个工厂方法,所以这种情况就具有一般性,不妨抽象出来,移动到抽象工厂角色Creator中加以声明。产品等级结构A和产品等级结构B的结构图如下所示。Java与模式·200·可以看出,每一个工厂角色都有两个工厂方法,分别负责创建分属不同产品等级结构的产品对象。系统的设计采用抽象工厂模式设计出的系统类图如下所示。从上图可以看出,抽象工厂模式涉及到以下的角色。抽象工厂(AbstractFactory)角色:担任这个角色的是工厂方法模式的核心,它是与应用系统的商业逻辑无关的。通常使用Java接口或者抽象Java类实现,而所有的具体工厂类必须实现这个Java接口或继承这个抽象Java类。具体工厂类(ConreteFactory)角色:这个角色直接在客户端的调用下创建产品的实例。这个角色含有选择合适的产品对象的逻辑,而这个逻辑是与应用系统的商业逻辑紧密相关的。通常使用具体Java类实现这个角色。第14章抽象工厂(AbstractFactory)模式·201·抽象产品(AbstractProduct)角色:担任这个角色的类是工厂方法模式所创建的对象的父类,或它们共同拥有的接口。通常使用Java接口或者抽象Java类实现这一角色。具体产品(ConcreteProduct)角色:抽象工厂模式所创建的任何产品对象都是某一个具体产品类的实例。这是客户端最终需要的东西,其内部一定充满了应用系统的商业逻辑。通常使用具体Java类实现这个角色。源代码下面给出这个系统所有的源代码。首先给出工厂角色的源代码,可以看出,抽象工厂角色规定出两个工厂方法,分别提供两个不同等级结构的产品对象。代码清单1:抽象产品角色的源代packagecom.javapatterns.abstractfactory;publicinterfaceCreator{/***产品等级结构A的工厂方法*/publicProductAfactoryA();/***产品等级结构B的工厂方法*/publicProductBfactoryB();}下面给出具体工厂角色ConcreteCreator1的源代码。这个具体工厂类实现了抽象工厂角色所要求的两个工厂方法,分别提供两个产品等级结构中的某一个产品对象。代码清单2:具体工厂类ConcreteCreator1的源代码packagecom.javapatterns.abstractfactory;publicclassConcreteCreator1implementsCreator{/***产品等级结构A的工厂方法*/publicProductAfactoryA(){returnnewProductA1();}/***产品等级结构B的工厂方法*/publicProductBfactoryB()Java与模式·202·{returnnewProductB1();}}一般而言,有多少个产品等级结构,就会在工厂角色中发现多少个工厂方法。每一个产品等级结构中有多少具体产品,就有多少个产品族,也就会在工厂等级结构中发现多少个具体工厂。下面给出具体工厂角色ConcreteCreator2的源代码。这个具体工厂类实现了抽象工厂角色所要求的两个工厂方法,分别提供两个产品等级结构中的另一个产品对象。代码清单3:具体工厂类ConcreteCreator2的源代码packagecom.javapatterns.abstractfactory;publicclassConcreteCreator2implementsCreator{/***产品等级结构A的工厂方法*/publicProductAfactoryA(){returnnewProductA1();}/***产品等级结构B的工厂方法*/publicProductBfactoryB(){returnnewProductB1();}}客户端需要的是产品,而不是工厂.在真实的系统中,产品类应当与应用系统的商业逻辑有密切关系。下面是产品等级结构A的抽象产品角色,在这个示意性的系统中,这个抽象产品角色是由一个Java接口实现的。代码清单4:具体产品类ProductA的源代码packagecom.javapatterns.abstractfactory;publicinterfaceProductA{}下面是属于产品等级结构A的具体产品类ProductA1的源代码。这个具体产品实现了产品等级结构A的抽象产品接口。代码清单5:具体产品类ProductA1的源代码packagecom.javapatterns.abstractfactory;publicclassProductA1implementsProductA第14章抽象工厂(AbstractFactory)模式·203·{publicProductA1(){}}下面是同样属于产品等级结构A的具体产品类ProductA2的源代码。这个具体产品也实现了产品等级结构A的抽象产品接口。代码清单6:具体产品类Pro
本文标题:抽象工厂模式
链接地址:https://www.777doc.com/doc-509419 .html