C# 中的抽象工厂设计模式

2025年3月17日 | 阅读 14 分钟

什么是抽象工厂设计模式?

  • Pattern 表示设计,Factory 表示产品生产地点,Abstract 表示某些信息的隐藏。因此,一种名为抽象工厂模式的软件设计模式提供了一种封装具有共同主题的独立工厂集合的方法。
  • 更简洁地说,抽象工厂可以被视为一个生产其他工厂的超级工厂。工厂的工厂是这种抽象工厂的另一个名称。
  • 这意味着,虽然具体工厂类负责实际的对象生产,但抽象工厂设计模式提供了一个用于构建相关或依赖产品族的接口。
  • 当一个系统必须独立于其结果的创建、组合和表示时,这种设计可能很有帮助。

抽象工厂模式的组成部分

抽象工厂设计模式的组成部分如下:

  • AbstractFactory:AbstractFactory 声明了用于生产抽象产品的操作的接口。这将作为生成抽象产品对象的进程的接口。
  • ConcreteFactory:ConcreteFactory 执行生产具体产品对象所需的进程。这些类提供了 Abstract Factory 接口以及接口方法的实现。借助这些具体类,可以创建具体产品对象。
  • AbstractProduct:描述了特定种类产品对象的接口。这些将是产品的创建接口。在此情况下,我们必须指定产品应具有的操作。ConcreteProduct 实现 AbstractProduct 接口。上述类执行 Abstract Product 接口。
  • Client:Client 使用 AbstractFactory 和 AbstractProduct 类声明的接口。此类将通过使用我们的抽象工厂和抽象产品接口来构建产品族。

使用 C# 理解抽象工厂设计模式的示例

让我们看一个现实世界的例子,以更好地理解抽象工厂设计模式。为了使概念易于理解,我们将首先创建示例,然后将其与抽象工厂设计模式的 UML 图进行比较。

我们希望实现一个显示汽车和自行车详细信息的应用程序。在这里,我们希望显示两种不同的自行车类型——普通型和运动型——以及两种不同的汽车类型——普通型和运动型——的详细信息。需要记住的是,汽车和运动型自行车属于同一个家族“运动型”。同样,普通汽车和普通自行车属于同一个家族“普通型”。考虑到这一点,让我们继续看看如何使用 C# 抽象工厂设计模式来实现这一点。

步骤 1:创建抽象产品

为了创建抽象产品,我们必须声明接口。在这里,我们需要为每种抽象产品类型开发两个接口或抽象类,因为我们将创建两种不同类型的通用对象,如汽车和自行车。我将在这里创建两个接口。

ICar.cs (ProductB_abstract)

在使用 ICar.cs 创建接口后,复制并粘贴以下代码。我们计划将其作为我们的第二个抽象产品发布。Car 产品族应为每种独特产品提供一个基本接口。在此实例中,SportsCar 和 RegularCar 版本的 Car 产品都必须实现 ICar 接口。正如您所见,我们已经开发了以下接口,ICar 接口的子类将实现它。它有一个抽象方法。

步骤 2:创建具体产品

在这种情况下,需要定义相关具体工厂将生产的具体产品对象。当我们稍后在教程中讨论具体工厂组件时,我们将讨论工厂如何生产产品对象。请记住,抽象产品接口必须由具体产品类实现。在我们的示例中,IBike 或 ICar 接口必须由具体产品类实现。因此,根据我们的规范,让我们创建四种具体产品——RegularCar、SportsCar、RegularBike 和 SportsBike。

RegularBike.cs (ProductA1)

创建名为 RegularBike.cs 的类文件后,能否将其中的代码插入其中?Bike 产品族包含以下普通自行车产品。它提供了 GetDetails 方法的实现,并且如您所见,它实现了 IBike 接口。

RegularCar.cs (ProductA2)

将以下代码复制并粘贴到名为 RegularCar.cs 的类文件中。Car 产品族包含以下普通汽车产品。正如您所见,它提供了 GetDetails 方法的实现,并且实现了 ICar 接口。

SportsCar.cs (ProductB2)

请通过复制粘贴将以下代码放入名为 SportsCar.cs 的类文件中。Car 产品族包含以下运动型汽车。正如您所见,它提供了 GetDetails 方法的实现,并且实现了 ICar 接口。

步骤 3:创建抽象工厂

在这种情况下,必须创建用于生成 AbstractProduct 对象的类的接口。在我们的示例中,它将是 IVehicleFactory。因此,将以下内容复制并粘贴到名为 IVehicleFactory.cs 的类文件中。如您所见,此类包含两个方法。CreateCar 方法创建各种汽车版本,而 CreateBike 方法创建各种自行车变体。请记住,在此情况下,我们仅声明方法并返回这两个方法的类型,它们是抽象产品 ICar 和 IBike。因此,我们可以从子类生成各种对象(即 ICar 和 IBike 子类的对象)。

注意:上面提到的抽象工厂类创建了一个工厂家族。让我们继续创建这种工厂家族。

步骤 4:创建具体工厂

为了构建具体产品对象,我们现在必须创建实现这些操作的具体类。这些类将实现抽象工厂接口以及两个接口方法。在我们的示例中,将创建两个具体类:RegularVehicleFactory 和 SportsVehicleFactory。ConcreteFactory。

RegularVehicleFactory.cs

RegularVehicleFactory 具体类将生成 Regular Vehicle 具体产品。在我们的场景中,Regular Car 和 Regular Bike 是 Regular Vehicle 具体产品。首先,创建一个名为 RegularVehicleFactory.cs 的类文件,然后粘贴并复制以下代码。请注意,虽然在过程中实例化了一个具体产品(new RegularBike 和 new RegularCar),但具体工厂方法的签名返回一个抽象产品(IBike)和(ICar)。因此,Regular 家族包含以下具体工厂,它生产 Regular Bike 和 Regular Car 产品。

SportsVehicleFactory (ConcreteFactory2)

SportsVehicleFactory 具体类将生成 Sports Vehicle 具体产品。在我们的示例中,SportsBike 和 SportsCar 是 Sports Vehicle 具体产品。首先,创建一个名为 SportsVehicleFactory.cs 的类文件,然后插入以下代码。显而易见,具体工厂的签名方法返回抽象产品(IBike 和 ICar),但方法本身实例化了一个具体产品(new SportsBike 和 new SportsCar)。因此,与同一运动家族相关的产品由以下具体工厂生产:运动自行车和运动汽车。

注意:在我们的示例中,客户端可以使用 IVehicleFactory 接口提供的接口来创建相关或依赖对象族。这里有 RegularVehicleFactory 和 SportsVehicleFactory 类,它们是该接口的两个具体实现。自行车和汽车是这两种类生产的两种不同类型的相关项目家族。RegularVehicleFactory 家族包含 RegularCar 和 RegularBike 类。相反,SportsVehicleFactory 家族包含 SportsCar 和 SportsBike 类。

步骤 5:客户端

Client 类使用 AbstractFactory 和 AbstractProduct 接口来构建相关对象族。在我们的示例中,它将是 Programme 类的 Main 方法。因此,对 Programme 类的 Main 函数进行以下更改。

输出

Abstract Factory Design Pattern in C#

抽象工厂设计模式 UML(类)图

Abstract Factory Design Pattern in C#

让我们检查一下构成抽象工厂设计模式的每个元素。

  • 抽象产品:这些将是创建抽象产品的用户界面。在此情况下,我们必须指定产品应具有的操作。在我们的示例中,它是 IBike.cs 和 ICar.cs 的接口。
  • 具体产品:实现抽象产品接口的类称为具体产品。在我们的示例中,具体产品是 RegularBike、SportsBike、RegularCar 和 SportsCar 类。
  • 抽象工厂:这将是一个用于生成抽象产品对象的类的接口。在我们的示例中,它将是 IVehicleFactory。
  • 具体工厂:这些类提供了 AbstractFactory 接口以及接口方法的实现。在我们的示例中,具体工厂类是 RegularVehicleFactory 和 SportsVehicleFactory。

C# 中的抽象工厂设计模式实际示例

让我们看一个实际示例,以演示 C# 中抽象工厂设计模式的分步实现。为了显示课程详情,我们希望创建一个单一的应用程序。我们希望在这里显示的两种课程类型是前端课程和后端课程。再次,我们需要向学生展示来源——即他们获取这些课程的途径。在此情况下,来源可能是离线或在线的。现在让我们继续探索如何使用 C# 中的抽象工厂设计模式来构建此应用程序。

步骤 1:创建抽象产品

为了创建抽象产品,我们必须在此位置声明接口。由于我们将创建两种类型的可识别产品,如课程和来源,因此我们需要为每种抽象产品类型开发两个接口或抽象类。我将在这里创建两个接口。

ICourse.cs

应将以下代码复制并粘贴到一个名为 ICourse.cs 的接口中。这将是其中一个抽象产品。Course 产品族应为每种独特产品提供一个基本接口。在此情况下,此 ICourse 接口需要由所有前端和后端课程产品变体实现。正如您所见,我们设计的接口具有三个抽象方法,前端课程和后端课程子类将实现它们。

ISource.cs

将以下代码复制并粘贴到一个名为 ISource.cs 的接口中。我们计划将其作为我们的第二个抽象产品发布。ISource 产品线中的每个独立产品都应该有一个基础接口。在此情况下,Online 和 Offline 版本的 Source 产品都必须实现 ISource 接口。正如您所见,我们仅使用一个抽象方法来生成以下接口。ISource 接口的 Online 和 Offline 子类将执行该过程。

步骤 2:创建具体产品

此时需要定义具体产品对象,即相关具体工厂将生产的实际产品对象。重要的是要记住,这些具体产品类需要实现接口方法和抽象产品接口。在我们的示例中,具体产品类需要实现 ICourse 或 ISource 接口。因此,根据我们的规范,让我们开发四种具体产品——FrontEndCourse、BackEndCourse、Online 和 Offline。

FrontEndCourse.cs

在名为 FrontEndCourse.cs 的类文件中,将其中的以下代码粘贴。Course 产品族包含以下 FrontEndCourse 产品。正如您所见,它实现了 ICourse 接口以及 ICourse 接口的所有三个方法。

步骤 3:创建抽象工厂

现在必须开发将生成抽象产品对象的类的接口。在我们的案例中,它将是 ISourceCourseFactory。将以下内容复制并粘贴到一个名为 ISourceCourseFactory.cs 的类文件中。如您所见,此类中的两个方法是 GetSource 和 GetCourse。GetSource 方法创建各种来源版本,而 GetCourse 方法创建各种课程版本。

在此声明中,我们仅说明这些方法和方法返回类型将是抽象产品,例如 ISource 和 ICourse。因此,我们可以从子类生成各种对象(即 ISource 和 ICourse 子类的对象)。

步骤 4:创建具体工厂

为了构建实际产品对象,我们需要设计实现抽象工厂接口的具体工厂类。我们的示例将创建两个具体类:OnlineSourceCourseFactory 和 OfflineSourceCourseFactory。

OnlineSourceCourseFactory .cs

OnlineSourceCourseFactory 具体类将为 Online Source 和 Course Concrete 生成产品。在我们的示例中,Online Source 和 Course Concrete 产品是 BackEndCourse 和 Online。首先,创建一个名为 OnlineSourceCourseFactory.cs 的类文件,然后插入以下代码。正如您所见,在过程中实例化了一个具体产品(new Online 和 new BackEndCourse),而具体工厂方法的签名返回了一个抽象产品(ICourse)和(ISource)。因此,OnlineSourceCourse Family 包含以下具体工厂,它生产 Online Source 和 BackEndCourse 产品。

OfflineSourceCourseFactory.cs

可以使用 OfflineSourceCourseFactory 具体类创建 Offline Sources 和 Courses 的具体产品。在我们的示例中,Offline Source 和 Course Concrete 产品是 FrontEndCourse 和 Offline。将以下代码复制并粘贴到 OfflineSourceCourseFactory.cs 类文件中。正如您所见,在过程中实例化了一个具体产品(new Offline 和 new FrintEndCourse)。同时,具体工厂方法的签名返回了一个抽象产品(ICourse)和(ISource)。因此,OfflineSourceCourse Family 包含以下具体工厂,它生产 Offline Source 和 FrontEndCourse 产品。

注意:在我们的示例中,客户端可以使用 ISourceCourseFactory 接口提供的接口来创建相关或依赖对象族。这里,我们有 OnlineSourceCourseFactory 和 OfflineSourceCourseFactory 类,它们是该接口的两个具体实现。这两种类——Courses 和 Sources——生产两种不同类型的相关对象族。OnlineSourceCourse 类家族包括 Online 和 BackEndCourse 类。然而,OfflineSourceCourse 家族包括 Offline 和 FrondEndCourse 类。

步骤 5:客户端

Client 类使用 AbstractFactory 和 AbstractProduct 接口来构建相关对象族。在我们的示例中,它将是 Programme 类的 Main 方法。因此,对 Programme 类的 Main 函数进行以下更改。

输出

Abstract Factory Design Pattern in C#

何时使用抽象工厂设计模式?

以下情况需要应用程序中使用抽象工厂设计模式:

  • 形成相关项目族:当您有一组旨在协同使用的相关项目时,您必须实现此限制。
  • 保持产品一致性:为了保证一致性和兼容性,您的应用程序只能使用同一家族中的产品。
  • 解耦具体实现:该模式有助于将客户端代码与其依赖的接口具体实现分离。
  • 促进产品家族交换:您的应用程序必须足够灵活,能够处理多个相关产品家族并快速在它们之间切换。
  • 提供抽象层:当生产复杂项目需要高度抽象时。这对于其创建需要配置或依赖项注入的系统特别有用。
  • 支持可伸缩性和可配置性:您的应用程序需要可伸缩性和可配置性,以便在不更改现有客户端代码的情况下引入新产品家族。
  • 特定于平台的实现:当您的程序必须与多个环境或平台一起工作时,每个平台都有必须实现的特定产品集。
  • 轻松进行模拟和测试:抽象工厂可以生成用于单元测试的模拟对象,从而简化了测试单个组件的过程。

抽象工厂与工厂方法设计模式的区别

尽管它们都是创建型设计模式,但它们在不同的上下文中使用并且具有独特的特性。理解它们的区别对于为给定设计问题选择合适的模式至关重要。

抽象工厂设计模式

  • 意图:通过接口,用户可以选择创建相关或依赖对象族,而无需声明它们的具体类。
  • 抽象性:处理旨在共享使用的一系列相关产品(家族)。
  • 实现:由多个生产过程组成,每个过程通常产生一种不同的产品。通常,抽象工厂定义了多种生产不同类型产品的方法。
  • 用例:当系统必须独立于其交互的产品生产过程时,将使用此模式。
  • 灵活性:由于它可以同时生成多个相关对象类型,因此具有更高的灵活性。
  • 复杂性:这种方法比工厂方法更复杂,因为它为产品族增加了一个额外的抽象层。

工厂方法设计模式

  • 意图:此类提供了一个对象创建接口,但允许子类选择要实例化的类。类可以使用工厂方法将对象创建委托给它们。
  • 抽象性:专注于单个产品,但它可以有多种变体。工厂方法模式专注于创建单个类型对象。
  • 实现:此方法使用单个生产过程来生产单一类型产品。子类覆盖该方法以更改生产的产品类型。
  • 用例:当一个类希望由其子类指定它创建的对象时,可以使用此模式。当一个类无法预测它必须创建的对象类别时,也经常使用它。
  • 灵活性:由于它处理特定项目,因此不如抽象工厂灵活,但更清晰。
  • 复杂性:由于只有一个产品需要关注,因此更容易实现和理解。

抽象工厂和工厂方法之间的主要区别

  • 创建范围:工厂方法创建单个产品,而抽象工厂管理多个相关或依赖产品的创建。
  • 抽象级别:由于抽象工厂处理产品族,因此它采用更高级别的抽象。
  • 创建控制:在抽象工厂中,创建通过对象组合完成;而在工厂方法中,通过继承(子类化)完成。
  • 用例:处理单个项目时使用工厂方法;否则,当您有大量可分组的对象时,使用抽象工厂。

结论

总之,C# 抽象工厂设计模式提供了一种封装相关对象族构建的方法,而无需指定它们的具体类。为工厂和产品定义接口可以促进客户端代码与实际实现之间的松散耦合,从而提高灵活性和可维护性。

总的来说,当开发需要创建相关对象族的系统时,抽象工厂设计模式是维护模块化、可扩展且易于维护代码的有用工具。