• Abstract Factory 抽象工厂模式简介与 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();
    }

      

    回到顶部

    二、抽象工厂模式的结构

    根据上一章节的示例代码,简单画一个 UML 图,如下:

    • AbstractFactory:声明一个创建抽象产品对象的操作接口。
    • ConcreteFactory:实现创建具体产品对象的操作。
    • AbstractProduct:为一类产品对象声明一个接口。
    • ConcreteProduct:定义一个将被相应的具体工厂创建的产品对象。实现了 IAbstractProduct 接口。
    • Client:仅使用由 AbstractFactory 和 AbstractProduct 类声明的接口。

    通常在运行时创建一个 ConcreteFactory 类的实例,此实例具有 AbstractFactory  中全部定义的实现。当客户端需要创建不同的产品对象时,可以通过实现抽象工厂来创建具体工厂。

    AbstractFactory  将产品对象的创建延迟到它的 ConcreteFactory 子类。

    回到顶部

    三、抽象工厂模式在 .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

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

    点击查看 OracleClientFactory.cs

    当然,诸如 Mysql、DB2 等类同。由此可见,当后续新增数据库时,只需对 DbProviderFactory 抽象工厂进行继承即可,对已实现的数据工厂毫无影响。
    
  • 相关阅读:
    阿里云服务器安装MySQL、Apache、PHP
    如何用Python搭建监控平台
    vant_radio组件实现勾选+取消勾选
    C++:符号的作用【::(命名空间、类、结构体作用域限定符)】【:(类的继承、初始化列表、)】【A.B(A必须为对象或结构体)】【A->B(箭头左边必须为指针),A只能是指向类、结构体、联合体的指针】
    C++成员指针
    Redis学习笔记【四】完结
    状态机图和活动图
    django问题记录
    【Linux】计算机的软硬件体系结构
    在Ubuntu Linux Desktop上构建matter开发环境
  • 原文地址:https://blog.csdn.net/2301_77550592/article/details/133236812