动机
在软件系统中,经常面临着“一系列相互依赖的对象”的创建工作;同时由于需求的变化,往往存在着更多系列对象的创建工作。如何应对这种变化?如何绕过常规的对象的创建方法(new),提供一种“封装机制”来避免客户程序和这种“多系列具体对象创建工作”的紧耦合?这就是我们要说的抽象工厂模式。
简介
抽象工厂模式,提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。——GOF
抽象工厂模式是所有形态的工厂模式中最为抽象和最具一般性的一种形态。抽象工厂模式是指当有多个抽象角色时,使用的一种工厂模式。抽象工厂模式可以向客户端提供一个接口,使客户端在不必指定产品的具体的情况下,创建多个产品族中的产品对象。根据里氏代换原则,任何接受父类型的地方,都应当能够接受子类型。因此,实际上系统所需要的,仅仅是类型与这些抽象产品角色相同的一些实例,而不是这些抽象产品的实例。换言之,也就是这些抽象产品的具体子类的实例。工厂类负责创建抽象产品的具体子类的实例。
结构
构成
AbstractFactory:抽象工厂接口,它里面应该包含所有的产品创建的抽象方法。
ConcreteFactory1/ConcreteFactory2:具体的工厂,创建具有特定实现的产品对象。
AbstractProductA/AbstractProductB:抽象产品,它们都有可能有两种不同的实现。
ProductA1/ProductA2/ProductB1/ProductB2:对两个抽象产品的具体分类的实现。
代码
测试程序:
class Program
{
static void Main(string[] args)
{
AbstractFactory factory1 = new ConCreateFactory1();
Client c1 = new Client(factory1);
c1.Run();
AbstractFactory factory2 = new ConCreateFactory2();
Client c2 = new Client(factory2);
c2.Run();
Console.Read();
}
}
抽象工厂:AbstractFactory
abstract class AbstractFactory
{
public abstract AbstractProductA CreateProductA();
public abstract AbstractProductB CreateProductB();
}
具体工厂1:ConCreateFactory1
class ConCreateFactory1 : AbstractFactory
{
public override AbstractProductA CreateProductA()
{
return new ProductA1();
}
public override AbstractProductB CreateProductB()
{
return new ProductB1();
}
}
具体工厂2:ConCreateFactory2
class ConCreateFactory2 : AbstractFactory
{
public override AbstractProductA CreateProductA()
{
return new ProductA2();
}
public override AbstractProductB CreateProductB()
{
return new ProductB2();
}
}
抽象产品A:AbstractProductA
abstract class AbstractProductA
{
}
抽象产品B:AbstractProductB
abstract class AbstractProductB
{
public abstract void Interact(AbstractProductA a);
}
具体产品ProductA1
class ProductA1 : AbstractProductA
{
}
具体产品ProductA2
class ProductA2 : AbstractProductA
{
}
具体产品ProductB1
class ProductB1 : AbstractProductB
{
public override void Interact(AbstractProductA a)
{
Console.WriteLine(this.GetType().Name+"interacts with"+a.GetType().Name);
}
}
具体产品ProductB2
class ProductB2 : AbstractProductB
{
public override void Interact(AbstractProductA a)
{
Console.WriteLine(this.GetType().Name+"interacts with"+a.GetType().Name);
}
}
客户端,使用环境
class Client
{
private AbstractProductA AbstractProductA;
private AbstractProductB AbstractProductB;
public Client(AbstractFactory factory) //构造,注意通过构造传入抽象工厂
{
AbstractProductB = factory.CreateProductB();
AbstractProductA = factory.CreateProductA();
}
public void Run()
{
AbstractProductB.Interact(AbstractProductA);
}
}
总结
优点
1.易于交换产品系统,由于具体工厂类,在一个应用中只需要在初始化的时候出现一次,这就使得改变一个应用的具体工厂变得非常容易,它只需要改变具体工厂即可使用不同的产品配置。
2.它让具体的创建实例过程与客户端分离,客户端是通过它们的抽象接口操纵实例,产品的具体类名也被具体工厂的实现分离,不会出现在客户代码中。
缺点
最大的缺点就是产品族扩展非常困难。如要增加一个产品C,也就是说有产品家族由原来的2个,增加到3个,抽象类AbstractCreator要增加一个方法createProductC(),然后,两个实现类都要修改——严重违反了开闭原则。
注意
在抽象工厂模式的缺点中,我们提到抽象工厂模式的产品族扩展比较困难,但是一定要清楚是产品族扩展困难,而不是产品等级,在该模式下,产品等级是非常容易扩展的,增加一个产品等级,只要增加一个工厂类负责新增加出来的产品生产任务即可,也就是说横向扩展容易,纵向扩展困难。
适用性
1.一个系统要独立于它的产品的创建、组合和表示时。
2.一个系统要由多个产品系统中的一个来配置时。
3.当你要强调一系列相关的产品对象的设计以便进行联合使用时。
4.当你提供一个产品类库,只想显示它们的接口不是实现时。