当前位置: 首页 > 滚动 > >正文

Abstract Factory Pattern 抽象工厂模式简介与 C# 示例【创建型】【设计模式来了】

来源:博客园    时间:2023-05-30 21:00:27
〇、简介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.DbProviderFactoryusing 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.SqlClientFactoryusing System.Data.Common;using System.Data.SqlClient;/// Represents a set of methods for creating instances of the  provider"s implementation of the data source classes.public sealed class SqlClientFactory : DbProviderFactory{/// Gets an instance of the . This can be used to retrieve strongly typed data objects.public static readonly SqlClientFactory Instance;internal SqlClientFactory(){}/// Returns a strongly typed  instance./// A new strongly typed instance of .public override DbCommand CreateCommand(){throw null;}/// Returns a strongly typed  instance./// A new strongly typed instance of .public override DbCommandBuilder CreateCommandBuilder(){throw null;}/// Returns a strongly typed  instance./// A new strongly typed instance of .public override DbConnection CreateConnection(){throw null;}/// Returns a strongly typed  instance./// A new strongly typed instance of .public override DbConnectionStringBuilder CreateConnectionStringBuilder(){throw null;}/// Returns a strongly typed  instance./// A new strongly typed instance of .public override DbDataAdapter CreateDataAdapter(){throw null;}/// Returns a strongly typed  instance./// A new strongly typed instance of .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#endregionusing 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 抽象工厂进行继承即可,对已实现的数据工厂毫无影响。

X 关闭

推荐内容

最近更新

Copyright ©  2015-2022 北极机械网版权所有  备案号:浙ICP备2022016517号-19   联系邮箱:514 676 113@qq.com