一句话解释:
提供一个接口,以创建一系列相关或相互依赖的抽象对象,而无需指定它们具体的类。(将一系列抽象类装进接口,一次接口实现,就必须实例化这一系列抽象类)
抽象工厂模式(Abstract Factory Pattern)是一种创建型模式。它用于创建一组相关对象的家族。强调的是一组对象之间的协作关系,而不是单个对象之间的依赖关系。抽象工厂类负责创建整个家族的对象的生命周期,并隐藏与实现有关的逻辑。
一个比喻:(科目与课代表)
语文和数学的课代表和副课代表,都按照抽象方法标准选好了,接下来同样的通过实现抽象类和接口标准,来选出两名物理课代表。当然,已经选出来的其他课代表,和本次选举无关联。
优点:
缺点:
总之,抽象工厂模式能够有效地封装对象创建,但是扩展产品较为困难。它在软件开发中被广泛使用,特别是在跨平台软件开发中经常用到,使用时要注意系统对象的特点合理使用。
适用场景:
实际使用场景举例:
总之,使用抽象工厂模式,都需要保证对象家族之间高内聚、松耦合,使得系统的设计和实现更加灵活和可扩展。
通过两个抽象类 ProductA/ProductBBBB,实现四个具体产品类;在通过接口 IAbstractFactory,实现两个具体工厂的产品族 ConcreteFactory1/ConcreteFactory2。最后通过 Client 类注入工厂类的同时,创建产品的不同产品的实例,使客户端不用了解产品如何实例化,可以直接引用。
// 抽象产品类。 | |
public abstract class ProductA | |
{ | |
public abstract void OperationA(); | |
} | |
public abstract class ProductBBBB | |
{ | |
public abstract void OperationBBBB(); | |
} | |
// 具体产品类,其中 ProductA1、ProductA2、ProductB1 和 ProductB2 分别代表不同的产品。 | |
public class ProductA1 : ProductA | |
{ | |
public override void OperationA() | |
{ | |
Console.WriteLine("ProductA1's operation."); | |
} | |
} | |
public class ProductA2 : ProductA | |
{ | |
public override void OperationA() | |
{ | |
Console.WriteLine("ProductA2's operation."); | |
} | |
} | |
public class ProductBBBB1 : ProductBBBB | |
{ | |
public override void OperationBBBB() | |
{ | |
Console.WriteLine("ProductBBBB1's operation."); | |
} | |
} | |
public class ProductBBBB2 : ProductBBBB | |
{ | |
public override void OperationBBBB() | |
{ | |
Console.WriteLine("ProductBBBB2's operation."); | |
} | |
} | |
// 抽象工厂接口,定义了各种不同产品族的生产方法。 | |
public interface IAbstractFactory | |
{ | |
ProductA CreateProductA(); | |
ProductBBBB CreateProductBBBB(); | |
} | |
// 每个具体工厂都能够生产特定的产品族。 | |
public class ConcreteFactory1 : IAbstractFactory | |
{ | |
public ProductA CreateProductA() | |
{ | |
return new ProductA1(); | |
} | |
public ProductBBBB CreateProductBBBB() | |
{ | |
return new ProductBBBB1(); | |
} | |
} | |
public class ConcreteFactory2 : IAbstractFactory | |
{ | |
public ProductA CreateProductA() | |
{ | |
return new ProductA2(); | |
} | |
public ProductBBBB CreateProductBBBB() | |
{ | |
return new ProductBBBB2(); | |
} | |
} | |
// 客户端代码使用抽象工厂来创建各种不同产品族的产品,而无需关心它们的实际实现。 | |
public class Client | |
{ | |
private readonly ProductA _productA; | |
private readonly ProductBBBB _productBBBB; | |
public Client(IAbstractFactory factory) | |
{ | |
_productA = factory.CreateProductA(); | |
_productBBBB = factory.CreateProductBBBB(); | |
} | |
public void Run() | |
{ | |
_productA.OperationA(); | |
_productBBBB.OperationBBBB(); | |
} | |
} |
// 测试 | |
static void Main(string[] args) | |
{ | |
Client client = new Client(new ConcreteFactory1()); | |
client.Run(); | |
Client client2 = new Client(new ConcreteFactory2()); | |
client2.Run(); | |
// 输出: | |
// ProductA1's operation. | |
// ProductBBBB1's operation. | |
// ProductA2's operation. | |
// ProductBBBB2's operation. | |
} |
下面我们尝试扩展出来一个新的产品 3:
// 具体产品类 | |
public class ProductA3 : ProductA | |
{ | |
public override void OperationA() | |
{ | |
Console.WriteLine("ProductA3's operation."); | |
} | |
} | |
public class ProductBBBB3 : ProductBBBB | |
{ | |
public override void OperationBBBB() | |
{ | |
Console.WriteLine("ProductBBBB3's operation."); | |
} | |
} | |
// 具体工厂都能够生产特定的产品族 | |
public class ConcreteFactory3 : IAbstractFactory | |
{ | |
public ProductA CreateProductA() | |
{ | |
return new ProductA3(); | |
} | |
public ProductBBBB CreateProductBBBB() | |
{ | |
return new ProductBBBB3(); | |
} | |
} |
测试:
static void Main(string[] args) | |
{ | |
Client client = new Client(new ConcreteFactory1()); | |
client.Run(); | |
Client client2 = new Client(new ConcreteFactory2()); | |
client2.Run(); | |
Client client3 = new Client(new ConcreteFactory3()); | |
client3.Run(); | |
} |
根据上一章节的示例代码,简单画一个 UML 图,如下:
通常在运行时创建一个 ConcreteFactory 类的实例,此实例具有 AbstractFactory 中全部定义的实现。当客户端需要创建不同的产品对象时,可以通过实现抽象工厂来创建具体工厂。
AbstractFactory 将产品对象的创建延迟到它的 ConcreteFactory 子类。
例如 DbProviderFactory,这个类位于 System.Data.Common.dll 程序集中,该类扮演抽象工厂模式中抽象工厂的角色,源码如下:
// System.Data.Common, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a | |
// System.Data.Common.DbProviderFactory | |
using System.Data.Common; | |
public abstract class DbProviderFactory | |
{ | |
private bool? _canCreateDataAdapter; | |
private bool? _canCreateCommandBuilder; | |
public virtual bool CanCreateDataSourceEnumerator => false; | |
public virtual bool CanCreateDataAdapter | |
{ | |
get | |
{ | |
if (!_canCreateDataAdapter.HasValue) | |
{ | |
using DbDataAdapter dbDataAdapter = CreateDataAdapter(); | |
_canCreateDataAdapter = dbDataAdapter != null; | |
} | |
return _canCreateDataAdapter.Value; | |
} | |
} | |
public virtual bool CanCreateCommandBuilder | |
{ | |
get | |
{ | |
if (!_canCreateCommandBuilder.HasValue) | |
{ | |
using DbCommandBuilder dbCommandBuilder = CreateCommandBuilder(); | |
_canCreateCommandBuilder = dbCommandBuilder != null; | |
} | |
return _canCreateCommandBuilder.Value; | |
} | |
} | |
public virtual DbCommand? CreateCommand() | |
{ | |
return null; | |
} | |
public virtual DbCommandBuilder? CreateCommandBuilder() | |
{ | |
return null; | |
} | |
public virtual DbConnection? CreateConnection() | |
{ | |
return null; | |
} | |
public virtual DbConnectionStringBuilder? CreateConnectionStringBuilder() | |
{ | |
return null; | |
} | |
public virtual DbDataAdapter? CreateDataAdapter() | |
{ | |
return null; | |
} | |
public virtual DbParameter? CreateParameter() | |
{ | |
return null; | |
} | |
public virtual DbDataSourceEnumerator? CreateDataSourceEnumerator() | |
{ | |
return null; | |
} | |
} |
下面是 SqlClientFactory.cs,继承了抽象类 DbProviderFactory,需要注意的是,此为引用程序集,即只包含元数据,不含可执行代码。如何通过工厂模式访问 SQLServer 数据库,可以参考官网示例: 获取 DbProviderFactory
点击查看 SqlClientFactory.cs
下面再看一下 Oracle 工厂的实现,完全独立于其他数据库的工厂:
点击查看 OracleClientFactory.cs
当然,诸如 Mysql、DB2 等类同。由此可见,当后续新增数据库时,只需对 DbProviderFactory 抽象工厂进行继承即可,对已实现的数据工厂毫无影响。