工厂方法把生产产品的方式封装起来了,但是一个工厂只能生产一类对象,当一个工厂需要生产多类产品的时候,就需要使用抽象工厂了。抽象工厂(Abstract Factory)类定义了一组标准的实现接口,这些接口一般都是和具体的产品类继承层次对应的。如CreateProductA接口只能生产抽象产品类(AbstratctProductA)的子类产品,因此抽象工厂的具体实现类之间的关系就是个生产了一批不同产品族的组合。这样通过抽象工厂模式可以方便的更换产品族,代码修改的代价只需要更换一个具体的工厂对象就可以了。因此直观上可以把抽象工厂看作一组工厂方法,它的每一个接口都可以提取出一个单独的工厂方法。不过抽象工厂除了反映出这些含义外,还隐含着多类产品之间有种内在的联系,如按钮、菜单、滚动条都是GUI组件。或者也可以这么理解:抽象工厂就是一组简单工厂的集合,抽象工厂中的每一个方法都对应一个具体的工厂。抽象工厂的类图如下:
涉及到的代码如下:
namespace Design_Patterns.Abstract_Factory
{
/// <summary>
/// 抽象工厂
/// <remarks>
/// 意图:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
/// 适用性:
/// 1:一个系统要独立于它的产品的创建,组合和表示时
/// 2:一个系统要由多个产品系列中的一个来配置时
/// 3:强调一系列相关的产品对象的设计以便进行联合使用时
/// 4:提供一个产品类库,而只想显示它们的接口而不是实现时
/// </remarks>
/// </summary>
public abstract class AbstractFactory
{
public abstract AbstractProductA CreateProductA();
public abstract AbstractProductB CreateProductB();
}
}
namespace Design_Patterns.Abstract_Factory
{
public abstract class AbstractProductA
{
public virtual void WriteProductMessage() { }
}
}
namespace Design_Patterns.Abstract_Factory
{
public abstract class AbstractProductB
{
public virtual void WriteProductMessage() { }
}
}
namespace Design_Patterns.Abstract_Factory
{
public abstract class AbstractProductB
{
public abstract void WriteProductMessage();
}
}
namespace Design_Patterns.Abstract_Factory
{
public class ConcreteFactory1 : AbstractFactory
{
public override AbstractProductA CreateProductA()
{
return new ProductA1();
}
public override AbstractProductB CreateProductB()
{
return new ProductB1();
}
}
}
namespace Design_Patterns.Abstract_Factory
{
public class ConcreteFactory2:AbstractFactory
{
public override AbstractProductA CreateProductA()
{
return new ProductA2();
}
public override AbstractProductB CreateProductB()
{
return new ProductB2();
}
}
}
namespace Design_Patterns.Abstract_Factory
{
public class ProductA1 : AbstractProductA
{
public override void WriteProductMessage()
{
Console.WriteLine(GetType());
}
}
}
namespace Design_Patterns.Abstract_Factory
{
public class ProductA2:AbstractProductA
{
public override void WriteProductMessage()
{
Console.WriteLine(GetType());
}
}
}
namespace Design_Patterns.Abstract_Factory
{
public class ProductB1:AbstractProductB
{
public override void WriteProductMessage()
{
Console.WriteLine(GetType());
}
}
}
namespace Design_Patterns.Abstract_Factory
{
public class ProductB2:AbstractProductB
{
public override void WriteProductMessage()
{
Console.WriteLine(GetType());
}
}
}
client方法定义如下:
namespace Design_Patterns.Abstract_Factory
{
public class RunDemo
{
public void Run()
{
AbstractFactory factory1 = new ConcreteFactory1();
/*IProductA productA = factory1.CreateProductA();
productA.WriteProductMessage();
IProductB productb = factory1.CreateProductB();
productb.WriteProductMessage();*/
AbstractFactory factory2 = new ConcreteFactory2();
/*productA = factory2.CreateProductA();
productA.WriteProductMessage();
productb = factory2.CreateProductB();
productb.WriteProductMessage();*/
Client clientA = new Client(factory1);
clientA.UseProduct();
Client clientB = new Client(factory2);
clientB.UseProduct();
}
}
public class Client
{
AbstractProductA productA = null;
AbstractProductB productB = null;
public Client(AbstractFactory factory)
{
productA = factory.CreateProductA();
productB = factory.CreateProductB();
}
public void UseProduct()
{
if (productA != null)
{
productA.WriteProductMessage();
}
if (productB != null)
{
productB.WriteProductMessage();
}
}
}
}
程序运行结果如下:
通过上述代码我们不难看出,相对于工厂方法或者简单工厂,抽象工厂给我们提供了一个更高层次的抽象,假如由于业务的变化或者产品的逐渐丰富,我们需要新增加一类产品,那么我们只需要添加新的工厂类并且继承AbstractFactory就可以完成了,而在新功能的增加过程中,我们并没有修改现有的所有代码,唯一需要改动的就是需要使用新产品的客户端。
其实抽象工厂的主要目的是隔离,通过工厂,客户端无需知道自己调用的具体实例是什么,但是同样的问题还是存在:抽象工厂由于共享了同一个基类,但是在实际的应用中很多子类可能会存在基类中没有的属性或者方法,如果要调用子类额外提供的方法,你就需要知道生成的类是否拥有调用的方法,解决的途径一般有2种:一种是在基类中体现,但是由于这个方法不是所有的子类都拥有,所以这种做法显然不合适,还有一种就是再次抽象一个接口或抽象类,多继承解决这个问题,当然了,多继承也是在架构设计中不推荐的一种做法,最好的实现方案是组合而不是集成,抽象一个新接口或者抽象类,定义子类中的某一类在基类中没有的特性,然后子类继承多个接口或抽象类并实现所有方法,但是这个要考虑不同的编程语言对于继承的一些限制。