Abstract Factory Pattern 抽象工厂模式简介与 C# 示例【创建型】【设计模式来了】
2023/5/31 1:22:42
本文主要是介绍Abstract Factory Pattern 抽象工厂模式简介与 C# 示例【创建型】【设计模式来了】,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
〇、简介
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# 示例【创建型】【设计模式来了】的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2022-03-01沐雪多租宝商城源码从.NetCore3.1升级到.Net6的步骤
- 2024-12-06使用Microsoft.Extensions.AI在.NET中生成嵌入向量
- 2024-11-18微软研究:RAG系统的四个层次提升理解与回答能力
- 2024-11-15C#中怎么从PEM格式的证书中提取公钥?-icode9专业技术文章分享
- 2024-11-14云架构设计——如何用diagrams.net绘制专业的AWS架构图?
- 2024-05-08首个适配Visual Studio平台的国产智能编程助手CodeGeeX正式上线!C#程序员必备效率神器!
- 2024-03-30C#设计模式之十六迭代器模式(Iterator Pattern)【行为型】
- 2024-03-29c# datetime tryparse
- 2024-02-21list find index c#
- 2024-01-24convert toint32 c#