〇、简介

1、什么是抽象工厂模式?

一句话解释:

  通过对抽象类和抽象工厂的一组实现,独立出一系列新的操作,客户端无需了解其逻辑直接访问。

抽象工厂模式(Abstract Factory Pattern)是一种创建型模式。它用于创建一组相关对象的家族。强调的是一组对象之间的协作关系,而不是单个对象之间的依赖关系。抽象工厂类负责创建整个家族的对象的生命周期,并隐藏与实现有关的逻辑。

 一个比喻:(科目与课代表)

  语文和数学的课代表和副课代表,都按照抽象方法标准选好了,接下来同样的通过实现抽象类和接口标准,来选出两名物理课代表。当然,已经选出来的其他课代表,和本次选举无关联。

2、优缺点和使用场景

优点:

  • 可以降低系统中各个对象之间的耦合度。
  • 隔离了具体类的生产,使得客户并不需要知道什么被创建。
  • 增加新的具体工厂和产品族很方便,无须修改已有系统,符合“开闭原则”。

缺点:

  • 在增加新的产品方面比较困难,需要修改抽象工厂的接口,这样会导致所有的具体工厂也需要做出相应的修改。
  • 抽象程度高,可能会导致一些底层实现细节难以控制。

总之,抽象工厂模式能够有效地封装对象创建,但是扩展产品较为困难。它在软件开发中被广泛使用,特别是在跨平台软件开发中经常用到,使用时要注意系统对象的特点合理使用。

 使用场景举例:

  • 游戏开发:游戏中可能需要多种角色、武器、敌人等元素,它们之间可能存在关联性或依赖性,可以使用抽象工厂方法来快速构建游戏元素。
  • 数据库访问组件设计:不同数据库的连接、查询和数据存储方式可能存在差异,可以使用抽象工厂方法来创建不同数据库的访问组件、驱动和映射器。
  • 操作系统界面设计:不同操作系统的界面设计具有不同的特点,可以使用抽象工厂方法来创建不同操作系统下的控件。

总之,使用抽象工厂模式,都需要保证对象家族之间高内聚、松耦合,使得系统的设计和实现更加灵活和可扩展。

一、抽象工厂模式简单实现与扩展

通过两个抽象产品类 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();
}

  

二、抽象工厂模式在 .net 框架中的实际应用

例如 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
 // System.Data.SqlClient, Version=4.6.1.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
// System.Data.SqlClient.SqlClientFactory
using System.Data.Common;
using System.Data.SqlClient; /// <summary>Represents a set of methods for creating instances of the <see cref="N:System.Data.SqlClient" /> provider's implementation of the data source classes.</summary>
public sealed class SqlClientFactory : DbProviderFactory
{
/// <summary>Gets an instance of the <see cref="T:System.Data.SqlClient.SqlClientFactory" />. This can be used to retrieve strongly typed data objects.</summary>
public static readonly SqlClientFactory Instance; internal SqlClientFactory()
{
} /// <summary>Returns a strongly typed <see cref="T:System.Data.Common.DbCommand" /> instance.</summary>
/// <returns>A new strongly typed instance of <see cref="T:System.Data.Common.DbCommand" />.</returns>
public override DbCommand CreateCommand()
{
throw null;
} /// <summary>Returns a strongly typed <see cref="T:System.Data.Common.DbCommandBuilder" /> instance.</summary>
/// <returns>A new strongly typed instance of <see cref="T:System.Data.Common.DbCommandBuilder" />.</returns>
public override DbCommandBuilder CreateCommandBuilder()
{
throw null;
} /// <summary>Returns a strongly typed <see cref="T:System.Data.Common.DbConnection" /> instance.</summary>
/// <returns>A new strongly typed instance of <see cref="T:System.Data.Common.DbConnection" />.</returns>
public override DbConnection CreateConnection()
{
throw null;
} /// <summary>Returns a strongly typed <see cref="T:System.Data.Common.DbConnectionStringBuilder" /> instance.</summary>
/// <returns>A new strongly typed instance of <see cref="T:System.Data.Common.DbConnectionStringBuilder" />.</returns>
public override DbConnectionStringBuilder CreateConnectionStringBuilder()
{
throw null;
} /// <summary>Returns a strongly typed <see cref="T:System.Data.Common.DbDataAdapter" /> instance.</summary>
/// <returns>A new strongly typed instance of <see cref="T:System.Data.Common.DbDataAdapter" />.</returns>
public override DbDataAdapter CreateDataAdapter()
{
throw null;
} /// <summary>Returns a strongly typed <see cref="T:System.Data.Common.DbParameter" /> instance.</summary>
/// <returns>A new strongly typed instance of <see cref="T:System.Data.Common.DbParameter" />.</returns>
public override DbParameter CreateParameter()
{
throw null;
}
}

下面再看一下 Oracle 工厂的实现,完全独立于其他数据库的工厂:

点击查看源码 OracleClientFactory.cs
#region 程序集 Oracle.ManagedDataAccess, Version=4.122.21.1, Culture=neutral, PublicKeyToken=89b483f429c47342
// C:\Users\zheng\.nuget\packages\oracle.manageddataaccess\21.10.0\lib\net462\Oracle.ManagedDataAccess.dll
// Decompiled with ICSharpCode.Decompiler 7.1.0.6543
#endregion using System;
using System.Data.Common;
using System.Security;
using System.Security.Permissions;
using OracleInternal.Common; namespace Oracle.ManagedDataAccess.Client
{
public sealed class OracleClientFactory : DbProviderFactory
{
public static readonly OracleClientFactory Instance = new OracleClientFactory(); public override bool CanCreateDataSourceEnumerator => true; public override DbCommand CreateCommand()
{
if (ProviderConfig.m_bTraceLevelPublic)
{
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Entry, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreateCommand);
} try
{
return new OracleCommand();
}
catch (Exception ex)
{
OracleException.HandleError(OracleTraceLevel.Public, OracleTraceTag.Error, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreateCommand, ex);
throw;
}
finally
{
if (ProviderConfig.m_bTraceLevelPublic)
{
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Exit, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreateCommand);
}
}
} public override DbCommandBuilder CreateCommandBuilder()
{
if (ProviderConfig.m_bTraceLevelPublic)
{
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Entry, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreateCommandBuilder);
} try
{
return new OracleCommandBuilder();
}
catch (Exception ex)
{
OracleException.HandleError(OracleTraceLevel.Public, OracleTraceTag.Error, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreateCommandBuilder, ex);
throw;
}
finally
{
if (ProviderConfig.m_bTraceLevelPublic)
{
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Exit, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreateCommandBuilder);
}
}
} public override DbConnection CreateConnection()
{
if (ProviderConfig.m_bTraceLevelPublic)
{
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Entry, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreateConnection);
} try
{
return new OracleConnection();
}
catch (Exception ex)
{
OracleException.HandleError(OracleTraceLevel.Public, OracleTraceTag.Error, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreateConnection, ex);
throw;
}
finally
{
if (ProviderConfig.m_bTraceLevelPublic)
{
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Exit, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreateConnection);
}
}
} public override DbConnectionStringBuilder CreateConnectionStringBuilder()
{
if (ProviderConfig.m_bTraceLevelPublic)
{
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Entry, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreateConnectionStringBuilder);
} try
{
return new OracleConnectionStringBuilder();
}
catch (Exception ex)
{
OracleException.HandleError(OracleTraceLevel.Public, OracleTraceTag.Error, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreateConnectionStringBuilder, ex);
throw;
}
finally
{
if (ProviderConfig.m_bTraceLevelPublic)
{
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Exit, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreateConnectionStringBuilder);
}
}
} public override DbDataAdapter CreateDataAdapter()
{
if (ProviderConfig.m_bTraceLevelPublic)
{
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Entry, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreateDataAdapter);
} try
{
return new OracleDataAdapter();
}
catch (Exception ex)
{
OracleException.HandleError(OracleTraceLevel.Public, OracleTraceTag.Error, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreateDataAdapter, ex);
throw;
}
finally
{
if (ProviderConfig.m_bTraceLevelPublic)
{
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Exit, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreateDataAdapter);
}
}
} public override DbDataSourceEnumerator CreateDataSourceEnumerator()
{
if (ProviderConfig.m_bTraceLevelPublic)
{
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Entry, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreateDataSourceEnumerator);
} try
{
return new OracleDataSourceEnumerator();
}
catch (Exception ex)
{
OracleException.HandleError(OracleTraceLevel.Public, OracleTraceTag.Error, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreateDataSourceEnumerator, ex);
throw;
}
finally
{
if (ProviderConfig.m_bTraceLevelPublic)
{
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Exit, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreateDataSourceEnumerator);
}
}
} public override DbParameter CreateParameter()
{
if (ProviderConfig.m_bTraceLevelPublic)
{
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Entry, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreateParameter);
} try
{
return new OracleParameter();
}
catch (Exception ex)
{
OracleException.HandleError(OracleTraceLevel.Public, OracleTraceTag.Error, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreateParameter, ex);
throw;
}
finally
{
if (ProviderConfig.m_bTraceLevelPublic)
{
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Exit, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreateParameter);
}
}
} public override CodeAccessPermission CreatePermission(PermissionState state)
{
if (ProviderConfig.m_bTraceLevelPublic)
{
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Entry, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreatePermission);
} try
{
return new OraclePermission(state);
}
catch (Exception ex)
{
OracleException.HandleError(OracleTraceLevel.Public, OracleTraceTag.Error, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreatePermission, ex);
throw;
}
finally
{
if (ProviderConfig.m_bTraceLevelPublic)
{
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Exit, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreatePermission);
}
}
}
}
}

当然,诸如 Mysql、DB2 等类同。由此可见,当后续新增数据库时,只需对 DbProviderFactory 抽象工厂进行继承即可,对已实现的数据工厂毫无影响。

Abstract Factory Pattern 抽象工厂模式简介与 C# 示例【创建型】【设计模式来了】的更多相关文章

  1. C#设计模式之四抽象工厂模式(AbstractFactory)【创建型】

    一.引言     写了3篇有关设计模式的文章了,大家有了些反馈,说能从中学到一些东西,我感到很欣慰,那就继续努力.今天我要写第四个模式了,该模式叫抽象工厂.上一篇文章我们讲了[工厂方法]模式,它是为了 ...

  2. C#设计模式之三抽象工厂模式(AbstractFactory)【创建型】

    一.引言 写了3篇有关设计模式的文章了,大家有了些反馈,说能从中学到一些东西,我感到很欣慰,那就继续努力.今天我要写第四个模式了,该模式叫抽象工厂.上一篇文章我们讲了[工厂方法]模式,它是为了解决[简 ...

  3. 简单工厂,Factory Method(工厂方法)和Abstract Factory(抽象工厂)模式

    对于简单工厂来说,它的工厂只能是这个样子的 public class SimplyFactory {  /** * 静态工厂方法 */ public static Prouct factory(Str ...

  4. 设计模式——(Abstract Factory)抽象工厂

    设计模式——(Abstract Factory)抽象工厂 设计面向对象软件比较困难,而设计可复用的面向对象软件就更加困难.你必须设计相关类,并设计类的接口和继承之间的关系.设计必须可以解决当前问题,同 ...

  5. 设计模式——(Abstract Factory)抽象工厂“改正为简单工厂”

    设计面向对象软件比较困难,而设计可复用的面向对象软件就更加困难.你必须设计相关类,并设计类的接口和继承之间的关系.设计必须可以解决当前问题,同时必须对将来可能发生的问题和需求也有足够的针对性.掌握面向 ...

  6. OOAD-设计模式(三)之创建型设计模式(5种)

    前言 前面介绍了OOAD的基础知识,现在我们来详细的说明一下GOF设计模式中的23种模式,希望大家能够学到东西! 一.工厂方法模式(Factory Method) 1.1.工厂方法模式概述 工厂方法模 ...

  7. python 设计模式之工厂模式 Factory Pattern (简单工厂模式,工厂方法模式,抽象工厂模式)

    十一回了趟老家,十一前工作一大堆忙成了狗,十一回来后又积累了一大堆又 忙成了狗,今天刚好抽了一点空开始写工厂方法模式 我看了<Head First 设计模式>P109--P133 这25页 ...

  8. 设计模式可复用面向对象软件设计基础之对象创建型模式—ABSTRACT FACTORY( 抽象工厂)

    意图 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类. 适用性 在以下情况可以使用 Abstract Factory模式 • 一个系统要独立于它的产品的创建.组合和表示时. • 一 ...

  9. 设计模式之美:Abstract Factory(抽象工厂)

    索引 别名 意图 结构 参与者 适用性 缺点 效果 相关模式 命名约定 实现 实现方式(一):使用 Factory Method 来实现 Abstract Factory. 实现方式(二):使用 Pr ...

  10. 设计模式(Abstract Factory)抽象工厂

    1. 需求: 设计一个电脑组装程序,对于组装品牌电脑. 用零件组装(主板.硬盘.显示器)由品牌提供的所有. 让我们组装一台联想电脑,板子.由联想提供. (眼下仅仅有Lenovo和Dell两种品牌) 2 ...

随机推荐

  1. python基础篇:Python基础知识,帮助初学者快速入门

    Python是一种高级编程语言,它易于学习和使用,因此成为了许多人的首选编程语言.本文将介绍Python的基础知识,以帮助初学者快速入门. 安装Python 在开始学习Python之前,您需要安装Py ...

  2. [C++STL教程]1.vector容器是什么?实用教程来啦!超简单易懂,拿来就用

    C++与传统的C语言有一个很大的区别,就是新增了标准模板库 STL(Standard Template Library),它是 C++ 标准库的一部分,不需要单独安装,只需要 #include 对应的 ...

  3. SpringBoot Windows 自启动 - 通过 Windows Service 服务实现

    SpringBoot 在Windows运行时,有个黑窗体,容易被不小心选中或关闭,或者服务器重启后,不能自动运行,注册为 Windows Service服务 可实现 SpringBoot 项目在Win ...

  4. c#动态执行字符串脚本(优化版)

    像javascript中有eval()来执行动态代码,c#中是没有的,于是自己动手丰衣足食, 先来代码 1 using System; 2 using System.Data; 3 using Sys ...

  5. ChatGPT如何助力DevOps|用例解读

    DevOps 是一种方法论,旨在提高软件开发和 IT 运营团队的协作和效率.DevOps 涉及各种任务和流程的自动化,例如规划.编码.测试.部署.监控和故障排除.然而,其中一些任务和流程仍然有大量任务 ...

  6. MySQL相关知识点思维导图整理

    MySQL相关知识点思维导图整理 Xmind思维导图下载地址: 蓝奏云:https://shuihan.lanzoui.com/iXZw7frkn5a

  7. 配置了一台3700X电脑后

        众所周知,电脑是生活中必不可少的玩具,最近搞了一套配置.CPU3700X,显卡RX580,内存32GB.敲,这CPU的框框,看见就爽的不得了. As we all know, a comput ...

  8. [Shell] Windows上支持Linux Shell的工具/方法

    0 概述 1 方式一 : Windows Terminal 局限性: 不支持 xargs等命令 支持sed,find等命令 安装方式 安装Windows Terminal的最简单方法是通过Micros ...

  9. [J2EE]SSM整合/Spring 与 MyBatis的整合【待续】

    参考文献 spring与mybatis五种整合方法 - 博客园/推荐

  10. LeeCode 动态规划(一)

    简述 如果某一问题存在很多重叠子问题,使用动态规划是非常有效的. 动态规划与贪心 贪心:每次都选择局部最优解 动态规划:每个状态都是由前一个状态推导得到 动态规划解题步骤 确定 dp数组 及下标的含义 ...