ξ 14.1 引言
☆ 抽象工厂模式的用意:抽象工厂模式可以向客户端提供一个接口,使得客户端在不必指定产品的具体类型的情况下,创建多个产品族中的产品对象。
☆ 对抽象工厂模式理解的三个步骤:
① 当系统中有多个抽象产品角色的时候,假设产生抽象产品角色的是实现了抽象工厂角色的具体工厂角色。
② 阶段一的假设无法成立,因为抽象产品角色无法被实例化。根据里氏替代原则,可以让具体工厂角色产生抽象产品角色的实现类,即具体产品角色。
③ 如果抽象产品角色有多个具体实例即具体产品角色,那么工厂(具体和抽象)角色应该提供不同的方法产生不同的具体产品角色。
ξ 14.2 问题
☆ 产品族:是指位于不同产品等级结构中,功能相关联的产品组成的家族。下图详细说明产品等级结构和产品族的关系:
从上图可以看出,对应的每一个产品族,都由一个具体工厂负责创建,在同一产品族中不同等级结构上的具体产品,由具体工厂的每个方法创建。
ξ 14.3 抽象工厂模式的结构
☆ 假设一个子系统需要一些产品对象,而这些产品又属于一个以上的产品等级结构。那么为了将消费这些产品对象的责任和创建这些产品对象的责任分割开,可以引入抽象工厂模式。这样的话,消费产品的一方不需要直接参与产品的创建工作,而只需要向一个公共的工厂接口请求所需要的产品。下面举例说明这种结构:
图中有两个等级结构,A和B。两个产品族1和2。可以看到,对于一个产品族有一个实现了抽象工厂角色的具体工厂角色(ProductA1和ProductA2对应ConcreteCreator1,ProductA2和ProductB2对应ConcreteCreator2),而同一个产品族内不同的等级结构,对应具体工厂角色里面的不同方法(ProductA1和ProductA2对应factoryA方法,ProductB1和ProductB2对应factoryB方法)。下面是源代码:
... {
ProductA factoryA();
ProductB factoryB();
}
public class ConcreteCreator1 implements Creator
... {
public ProductA factoryA()
...{
return new ProductA1() ;
}
public ProductB factoryB()
...{
return new ProductB1() ;
}
}
public class ConcreteCreator2 implements Creator
... {
public ProductA factoryA()
...{
return new ProductA2() ;
}
public ProductB factoryB()
...{
return new ProductB2() ;
}
}
public interface ProductA
... {
}
public class ProductA1 implements ProductA
... {
public ProductA1() ...{}
}
public class ProductA2 implements ProductA
... {
public ProductA2() ...{}
}
public interface ProductB
... {
}
public class ProductB1 implements ProductB
... {
public ProductB1() ...{}
}
public class ProductB2 implements ProductB
... {
public ProductB2() ...{}
}
ξ 14.4 在什么情况下应该使用抽象工厂模式
① 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有形态的工厂模式都是很重要的;
② 这个系统的产品有多于一个的产品族,而系统只消费其中某一族的产品;
③ 同属于同一个产品族的产品是在一起使用的,这一约束必须在系统的设计中体现出来。
④ 系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于实现。
ξ 14.7 “开-闭”原则
当抽象工厂模式中新加产品族的时候,只需要添加抽象工厂角色和抽象产品角色的具体角色并建立起相应的关系就可以,这个时候抽象工厂模式是支持“开-闭”原则的;
当增加产品等级结构时,需要改动抽象工厂角色和修改每个具体工厂角色,这个时候,抽象工厂模式是不满足“开-闭”原则的。
综合来看,抽象工厂模式以一种倾斜的方式支持增加新的产品,它为新产品族的增加提供方便,而不能为新的产品等级结构的增加提供这样的方便。
=============================
最后总结一下:
☆ 首先举一个比较具体的例子。在UI设计中,一般会有许多控件,比如按钮(Button)和文本框(Text),这里Button和Text就是两个等级结构的产品。而为了在Windows和Macintosh系统中提供不同的效果,需要有Windows Button、Windows Text,同理会有Macintosh Button和Macintosh Text,这里Windows和Macintosh就是两个产品族,下图说明了它们之间的关系:
下面是源代码:
public interface Factory
... {
// 创建按钮
Button createButton();
// 创建文本框
Text createText();
}
// 下面是Factory接口的默认实现,这里使用了默认适配模式
public abstract class AbstractFactory implements Factory
... {
// 抽象方法,派生类实现
public abstract Button createButton();
// 抽象方法,派生类实现
public abstract Text createText();
// 根据标识选择创建何种具体工厂角色(选择产品族)
public static Factory getFactory(String flag)
...{
Factory result = null ;
if( flag.equalsIgnoreCase("macintosh") )
...{
result = MacFactory.getInstance() ;
}
else if( flag.equalsIgnoreCase("windows") )
...{
result = WinFactory.getInstance() ;
}
return result ;
}
}
// 下面是Macintosh产品族的具体工厂角色
public class MacFactory extends AbstractFactory
... {
// 单例模式,私有构造函数
private MacFactory() ...{}
// 创建Macintosh产品族按钮
public Button createButton()
...{
return new MacButton() ;
}
// 创建Macintosh产品族文本框
public Text createText()
...{
return new MacText() ;
}
// 提供单例的方法
synchronized public static Factory getInstance()
...{
if( null == _instance )
_instance = new MacFactory() ;
return _instance ;
}
private static MacFactory _instance = null ;
}
// 下面是Widnows产品族的具体工厂角色
public class WinFactory extends AbstractFactory
... {
// 单例模式,私有构造函数
private WinFactory() ...{}
// 创建Widnows产品族按钮
public Button createButton()
...{
return new WinButton() ;
}
// 创建Widnows产品族文本框
public Text createText()
...{
return new WinText() ;
}
// 提供单例的方法
synchronized public static Factory getInstance()
...{
if( null == _instance )
_instance = new WinFactory() ;
return _instance ;
}
private static WinFactory _instance = null ;
}
// 下面是等级结构中Button的抽象产品角色
public interface Button
... {
}
// 下面是Button的Macintosh产品族具体产品角色
public class MacButton implements Button
... {
public MacButton() ...{}
}
// Button的Windows产品族具体产品角色
public class WinButton implements Button
... {
public WinButton() ...{}
}
// 等级结构中Text的抽象产品角色
public interface Text
... {
}
// Text的Macintosh产品族具体产品角色
public class MacText implements Text
... {
public MacText() ...{}
}
// Text的Windows产品族具体产品角色
public class WinText implements Text
... {
public WinText() ...{}
}
☆ 下面给出三种常见形态的工厂模式的相图,依次是抽象工厂模式、工厂方法模式和简单工厂模式: