抽象工厂模式
# 分类
创建型模式
# 定义
抽象工厂模式(Abstract Factory Pattern) 围绕一个超级工厂
创建其他工厂,该超级工厂又称为其他工厂的工厂。在抽象工厂模式中,接口负责创建一系列相关或相互依赖的对象,不需要显式指定它们的类,每个生成的工厂都能按照工厂方法模式提供对象。
# 意图
抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们的具体类型。
# 应用场景
- 如果您的客户程序希望将业务逻辑和产品创建相分离,把一系列产品的创建,甚至
一系列中某些产品的组合
全部放在抽象工厂内部解决。 - 当你要强调一系列相关产品对象的设计,便于
客户程序集中调用
时。 - 当然,您也可以让抽象工厂
“大材小用---实际当做工厂方法使用”
,为了简化创建部分的接口,即便客户程序当前只需要某一类产品,为了省去以后再去把那些可以预见到的相关类型维护到类库里的工作量,先把它们加到一个抽象工厂里面。
应用案例
- QQ换皮肤一整套一起换。
- 网站或软件一键更换主题。
# 角色与结构图
- IProductA:
产品A接口角色
定义产品A的抽象方法。 - IProductB:
产品B接口角色
定义产品B的抽象方法。 - IAbstractFactory:
工厂接口角色
定义一系列产品生成的方法。 - ConcreteProductA:
具体产品A角色
实现 IProductA接口中定义的方法。 - ConcreteProductB:
具体产品B角色
实现 IProductB接口中定义的方法。 - ConcreteFactoryA:
具体工厂A角色
实现 抽象工厂中定义的方法。 - ConcreteFactoryB:
具体工厂B角色
实现 抽象工厂中定义的方法。 - Client:客户程序,使用 IAbstractFactory 以及 IProductA 、IProductB 实现功能。
下图解释了抽象工厂模式中各角色的作用

# 示例代码
/// 定义不同类型的抽象产品
public interface IProductA { }
public interface IProductB { }
/// 定义实体产品
public class ProductA1 : IProductA { }
public class ProductA2 : IProductA { }
public class ProductB1 : IProductB { }
public class ProductB2 : IProductB { }
2
3
4
5
6
7
8
9
/// 定义抽象工厂
public interface IAbstractFactory
{
IProductA CreateProductA();
IProductB CreateProductB();
}
///实体工厂
public class ConcreteFactory1 : IAbstractFactory
{
public virtual IProductA CreateProductA(){return new ProductA1();}
public virtual IProductB CreateProductB() { return new ProductB1(); }
}
public class ConcreteFactory2 : IAbstractFactory
{
public virtual IProductA CreateProductA() { return new ProductA2(); }
public virtual IProductB CreateProductB() { return new ProductB2(); }
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//客户端程序
class Client{
public void Main(string[] args)
{
IAbstractFactory factory = new ConcreteFactory2();
IProductA productA = factory.CreateProducctA();
IProductB productB = factory.CreateProducctB();
}
}
2
3
4
5
6
7
8
9
# 优点
当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
# 缺点
产品族扩展非常困难,要增加一个系列的某一产品,既要在抽象的Factory里加代码,又要在具体的类里面加代码。
# 小结
- 抽象工厂模式是工厂方法的升华,它除了解决对象构造过程后置之外,更主要的是提供了一组“相关或具有依赖关系对象”的创建过程,也就是具有了对一组类型构造过程组合和调度的能力;相对工厂方法而言,它更像一个“封装”的工厂,而不是简单地提供创建某个类型产品的“方法”。
- 使用中可以把简单工厂、静态工厂、工厂方法和抽象工厂混合起来使用。
一个建议的布局是这样的
- 静态工厂可以作为最底层的一个“泵”,它提供最原始但最粗颗粒度对象的创建,甚至生成object,后绑定调用(或被称为晚绑定)可以通过一个集中的静态工厂完成。之所以把它放在最下面,主要是因为它不能被继承和进一步扩展,所以让它做最基本但又最通用的工作。实际工程中完全用Activator充当这个角色。
- 简单工厂方法的适用范围很广,根据应用的需要在某些需要隔绝抽象与具体的位置上使用。
- 工厂方法应用在具有一套较纵深层次的对象上,可以通过实体工厂类型选择继承层次上一个合适的具体产品来构造,而客户程序则把握住抽象的工厂类型和抽象的产品类型即可。
- 抽象工厂方法则用在某些应用领域上,面向某些应用子系统或专业领域的对象创建工作,相对而言我们可以更多地把它应用于项目的中高层设计中。
- 抽象工厂模式 + 反射 + 配置文件,可以实现依赖注入,依赖注入一般需要专门的IoC容器提供。
反射
Assembly.Load("程序及名称").CreateInstance("命名空间.类名称")
简单工厂模式和工厂方法模式,它们的核心目标都是一致的:直接由客户程序创建对象的时候,由于目标对象本身可能会经常变化,但它们的抽象能力却相对固定,因此我们需要通过工厂把这个创建过程封装出来,让客户程序不需自己new()目标类型。
简单工厂方法的职责非常简单:构造某个实体类型,然后把实例作为抽象类型返回;工厂方法则进一步抽象出一个抽象的创建者和一个抽象的产品类型,而实际的执行过程是具体工厂创建具体的产品类型,不过,因为具体工厂和具体产品类型都可以被抽象为之前定义的抽象创建者和抽象产品类型,因此即便面对一个很庞大的具有复杂家族关系的类型系统,客户程序在操作的过程中也可以基于抽象创建者获得满足某种抽象类型的产品实例。
主要解决?主要解决接口选择问题。
何时使用?系统的产品有多于一个的产品族,而系统只消费其中某一族的产品。
如何解决?在一个产品族里面,定义多个产品。
关键代码?在一个工厂里聚合多个同类产品。
注意:产品族难扩展,产品等级易扩展。
# 大结
常规对象创建方法:new,实现依赖,不能应对”具体实例化类型”的变化。解决思路:封装变化点,哪里有变化,封装哪里。如果没有变化,当然不需要额外的封装。不是见到new就需要封装,如果一个类型非常稳定就不需要封装成工厂。工厂模式的缘起:变化点在对象创建,因此就封装对象创建。面向接口编程,依赖接口,而非依赖实现。起点:简单工厂模式(静态工厂方法)。动机:在软件系统中,经常面临一系列相互依赖的对象的创建工作,同时,由于需求的变化,往往存在更多系列对象的创建工作。如何应对这种变化?如何绕过常规的对象创建方法(new),提供一种封装机制来避免客户程序和这种多系列具体对象创建工作的紧耦合。意图:提供一个接口,让该接口负责创建一系列相关或者相互依赖的对象,无需指定他们具体的类。注意:如果没有应对“多系列对象构建”的需求变化,则没有必要使用抽象工厂模式,这时候使用简单的静态工厂完全可以;“系列对象”指的是这些对象之间有相互依赖、或作用的关系,例如游戏开发场景中的“道路”与“房屋”的依赖,“道路”与“地道”的依赖;抽象工厂模式主要在于应对“新系列”的需求变动。其缺点在于难以应对“新对象”的需求变动;抽象工厂模式经常和工厂方法模式共同组合来应对“对象创建”的需求变化。
# 一句话概括
创建一系列相关或依赖对象的家族,而无需明确指定具体类。