C# 中的建造者设计模式

2025年2月5日 | 阅读10分钟

关于建造者设计模式?

GOF 声称,建造者设计模式使用分步方法和众多简单组件来构建复杂对象。在 C# 中创建具有许多必需和可选字段的对象时,建造者设计模式非常方便,特别是当对象的开发过程很复杂或存在对象的多种潜在表示时。

目标是将复杂对象的表示与其生产解耦,以便可以使用相同的构建过程生成不同的表示。

该模式仅应在对象开发极其复杂时应用。

示例

在这种情况下,笔记本电脑是一个复杂的项目。组装笔记本电脑需要许多小部件,包括 LCD 屏幕、USB 端口、无线模块、硬盘、指点设备、电池、内存、DVD/CD 读取器、键盘、塑料外壳等。我们必须将所有这些小部件组合在一起,以构建笔记本电脑的复杂对象。

Builder Design Pattern in C#

因此,我们需要构建一些通用程序,如下所示,以构建具有复杂对象的笔记本电脑。

  1. 插入内存
  2. 插入硬盘
  3. 插入电池
  4. 插入键盘
  5. 在笔记本电脑上放置塑料外壳。

因此,我们可以使用相同的方法制作多种笔记本电脑类型,包括 14 英寸或 17 英寸屏幕的笔记本电脑。笔记本电脑的内存可以是 8GB 或 4GB RAM。通过这种方式,我们可以生产多种类型的计算机。因此,所有笔记本电脑的生产都将遵循通用技术。如果您已阅读此内容,现在应该能够理解建造者设计模式的含义。它在构建具有大量附加组件或配置的对象时非常有用。

示例

假设我们希望创建一个程序来显示报告。我们必须以 PDF 或 Excel 格式呈现报告,这表明报告以两种不同的方式表示。请查看附图以更好地理解这一点。

Builder Design Pattern in C#

上图说明我们以 Excel 和 PDF 格式生成报告。必须创建新报告并定义其报告类型、标题、内容和页脚,这是构建过程中的其他阶段。要了解构建过程及其表示方式,请参阅附图。

Builder Design Pattern in C#

理解 UML

请参考以下图表以理解这一点。

Builder Design Pattern in C#

建造者设计模式包含四个协同工作的元素,它们将创建过程与其描述分离。它们列举如下。

抽象建造者:建造者包含一个接口,其中概述了创建具体输出所涉及的每个步骤。

指导者:指导者使用建造者提供的不同程序来建立产品构建的顺序。

产品:产品是一个类,我们希望使用建造者设计模式生成该类的一个对象。该类定义了构成最终产品的几个组件。

注意:在查看示例后,我们将将其与上面的 UML 图以及我们的示例与上面提到的组件进行对比。之后,您可能会理解建造者设计模式的各种组件以及上面的 UML 图。

C# 中建造者设计模式的实现

步骤 1:创建产品

以下代码应复制并粘贴到名为 Report.cs 的类文件中。我们在此产品类中指定了构建报告所需的通用属性(如 ReportHeader、ReportType、ReportFooter 和 ReportContent)。还定义了一个名为 DisplayReport 的方法,用于在控制台中显示报告详细信息。

一旦我们确定了正在生产的产品的定义,我们必须立即设计建造者。

步骤 2:创建类。

这个抽象类将作为开发各种产品类型的指南。鉴于它是抽象的,它可以同时具有抽象和非抽象过程。此 ReportBuilder 抽象类中的所有抽象方法都必须有实现,这些实现必须由子类提供。

为了正确创建报告,ReportBuilder 的所有子类都必须实现这四个抽象方法。

步骤 3:创建建造者类。

具体建造者类提供构建步骤的具体实现,它们遵循建造者接口。应用程序中的建造者可能会有许多不同的实现版本。因此,必须实现 ReportBuilder 抽象类,并且必须实现 ReportBuilder 抽象方法以生成两个具体的建造者类。

ExcelReport.cs

将以下代码粘贴到名为 ExcelReport.cs 的类文件中。ExcelReport 类实现了四个抽象方法和 ReportBuilder 抽象类,它们是构建报告对象的蓝图。此类提供了 Excel 报告创建蓝图。

PDFReport.cs

将以下代码复制并粘贴到名为 PDFReport.cs 的类文件中。此类还实现了生成报告对象的蓝图、四个抽象方法和 ReportBuilder 抽象类。要以 PDF 格式构建报告,请使用下面的 PDFReport 类。

在拥有必要的具体建造者类后,必须创建指导者。指导者将按照特定顺序执行必要的动作以产生特定结果。

步骤 4:创建指导者

在建造者设计模式中,指导者类专门负责按顺序执行构建过程。由于这些过程非常通用,它们将产生许多产品。在根据特定配置或顺序创建商品时,它很有用。

类中唯一的通用方法是 MakeReport,它在接收 ReportBuilder 实例作为输入参数后创建并返回一个特定的报告对象。

由于其极高的通用性,MakeReport 方法可以生成并返回各种报告对象。一旦我们获得它们,客户端就可以使用指导者和具体建造者来构建各种报告类型。我们示例中的客户端只是程序类的 Main 函数。

步骤 5:客户端代码

在建造者设计模式中,客户端代码创建建造者对象,该对象被传递给指导者,然后指导者开始构建过程。最后剩下的唯一事情是从建造者对象中提取产品。

因此,请按照如下所示修改程序类的 Main 方法。在这种情况下,将首先创建 ReportDirector 类的一个实例,然后创建 PDFReport 类的一个实例。

建造者设计模式组件

为了帮助您理解 UML 图,我们允许您使用我们的示例展示建造者设计模式 UML 图组件。

Builder Design Pattern in C#

实时示例

Builder Design Pattern in C#

正如我们已经介绍过的,C# 中的建造者设计模式用于通过通用、分步的过程构建复杂对象,以便可以使用相同的构建过程或阶段构建相同复杂对象的不同表示。您可以看到这两个实例都使用相同的方法制作茶和咖啡——只是物质不同。因此,您可以设计一个单一的通用过程,如下所示。

Builder Design Pattern in C#

现在,这个通用程序可以用来制作茶、咖啡、好立克等。您可以使用建造者设计模式在任何编程语言中轻松实现上述内容。现在,让我们探讨如何在 C# 中使用建造者设计模式来构建上述实时应用程序。

C# 中建造者设计模式的实时示例——饮料

让我们逐步使用 C# 中的建造者设计模式来实现上述实时示例。

步骤 1:饮料产品创建

仅当您的物品复杂且需要大量自定义时,使用建造者设计模式才有意义。

步骤 2:创建抽象建造者 (BeverageBuilder)

将以下内容粘贴到名为 BeverageBuilder.cs 的类文件中。抽象的 BeverageBuilder 类将作为任何希望生产饮料的子类的模型。因此,它将有许多针对不同饮料类型(包括好立克、咖啡和茶)的子类实现。

步骤 3:创建具体建造者(CoffeeBuilder 和 TeaBuilder)

在我们的示例中,我们将制作两种不同类型的饮料:茶和咖啡。因此,通过实现 BeverageBuilder 抽象类并为所有抽象方法提供实现,我们必须创建两个具体的建造者类。

TeaBuilder.cs

请将以下代码复制并粘贴到名为 TeaBuilder.cs 的类文件中。此外,此类别为所有抽象方法提供实现,并实现抽象的 BeverageBuilder 类。以下是 TeaBuilder 课程。

步骤 4:创建指导者 (BeverageDirector)

在构建具体建造者类之后,必须创建指导者。指导者只剩下按顺序执行构建步骤的任务。在根据特定配置或顺序创建商品时,它很有用。

指导者将按照特定顺序执行必要的动作以生产饮料。为了使用此代码,请创建一个名为 BeverageDirector.cs 的类文件并复制粘贴它。此类包含一个通用方法,该方法在接收 BeverageBuilder 作为输入参数后创建并返回一个特定的饮料对象。

步骤 5:客户端代码。

请按如下所示调整 Main 方法。在这里,我们将在创建 BeverageDirector 类的实例之前,先创建一个 TeaBuilder 类的实例。在获取 TeaBuilder 和 BeverageDirector 的实例后,我们使用 BeverageDirector 实例调用 MakeBeverage 方法,省略 TeaBuilder 实例作为参数,这将生成并产生茶。要准备咖啡,我们必须再次遵循相同的程序。

何时使用 C# 建造者设计模式?

C# 建造者设计模式在以下情况中很有用

复杂对象构建:这指的是需要复杂过程来创建对象的情况,特别是如果涉及多个步骤或创建多个子对象。

创建不可变对象:如果您需要构建不可变对象或创建后无法更改的对象,建造者模式允许您在创建时设置所有必需的属性。

构建具有许多参数的对象:构建一个项目需要大量参数,其中一些参数可能不是必需的。与使用多个构造函数相比,建造者模式提供了更具可读性和可理解性的方法(伸缩构造函数反模式)。

可读的对象创建:这提高了代码的可读性和可维护性,特别是当对象的创建需要许多参数时,如果使用简单的构造函数,这些参数可能会令人困惑。

可重用对象创建逻辑:建造者可以集中存储和封装需要在许多应用程序组件中重用的对象创建逻辑。

流畅接口:当您希望提供一种对象创建过程,以一种使客户端代码更易于阅读的方式引导客户端完成创建过程的每个步骤时,可以使用这些接口。

可配置对象创建:在创建具有各种配置的对象时,各种场景需要对象特征的不同组合。

C# 建造者设计模式的优点

在 C# 编程中,建造者设计模式具有许多优点,尤其是在处理复杂的对象构建时。主要优点包括

  • 构建与表示的分离:建造者模式通过将项目的生产与其表示分离,可以使用相同的构建过程创建不同的表示。现在已经进行了这种分离,代码更具模块化。
  • 增强的可读性和可维护性:通过使用建造者模式,可以避免伸缩构造函数反模式——即构造函数具有多个不一定必需的参数。
  • 对象实例化的灵活性:建造者可以创建通常需要大量设置代码的复杂对象。此外,它们还可以实例化不可变类子类。
  • 添加新参数的简易性:使用建造者向对象的构造函数添加新参数很简单,并且不涉及更改构造函数签名,这使得当前的客户端代码不受影响。

C# 建造者设计模式的缺点

虽然建造者设计模式在组织和清晰开发复杂事物方面提供了许多优点,但它也有几个缺点,尤其是在 C# 开发方面

  • 增加的复杂性:指导者和具体建造者是建造者模式引入的额外层和对象的两个例子。这些可能会使代码过于复杂,特别是对于可能不需要如此复杂创建过程的基本项目。
  • 代码重复:由于建造者的属性有效地复制了正在生产的对象的属性,因此可能会出现代码重复。
  • 效率问题:逐件构建东西效率可能较低,特别是如果最终产品很复杂。
  • 维护开销:维护建造者模式可能很困难,因为这些更改可能需要在关联的建造者类中反映出来,特别是如果底层对象的结构经常更改。
  • 不可变性困难:虽然建造者模式非常适合生产不可变对象,但保持不可变性有时可能很困难,特别是如果最终产品在生产后需要修改。
  • 理解和学习曲线:与简单的对象构建过程相比,该模式可能会给不熟悉它的开发人员带来学习曲线,并使代码在第一眼时更难理解。
  • 潜在的滥用:当不太复杂的对象生成技术就足够时,建造者模式可能会被滥用,从而增加不必要的复杂性和抽象。

结论

总之,C# 建造者设计模式提供了一种整洁灵活的方式来创建具有大量可配置选项的复杂对象。它通过将构建过程与项目表示分离,可以使用相同的构建方法生成多个对象变体。这种风格将对象构建逻辑隔离到不同的建造者类中,这有助于代码的灵活性、可维护性和可重用性。

通过利用建造者设计模式,您可以快速扩展系统以生成具有不同配置的多种披萨品种,而无需更改客户端代码。这通过使程序更具模块化和适应变化,从而提高了整体可维护性和可伸缩性。