建造者模式:优雅构建复杂对象

news2025/6/5 19:04:54

引言

在软件开发中,有时我们需要创建一个由多个部分组成的复杂对象,这些部分可能有不同的变体或配置。如果直接在一个构造函数中设置所有参数,代码会变得难以阅读和维护。当对象构建过程复杂,且需要多个步骤时,我们可能会陷入"伸缩式构造函数"的困境,或者创建大量的子类来处理各种组合。

建造者模式(Builder Pattern)提供了一种更优雅的解决方案,它将一个复杂对象的构建过程与其表示分离,使得同样的构建过程可以创建不同的表示。这种模式特别适用于需要分步骤创建复杂对象的场景,或者当对象的创建涉及大量参数时。

本文将深入探讨建造者模式的概念、实现方式、应用场景以及优缺点,并通过C#代码示例来展示其实际应用。

文章目录

    • 引言
    • 建造者模式定义
    • 建造者模式的UML类图
    • 建造者模式的组成部分
    • 建造者模式的实现方式
      • 基本实现
      • 使用链式调用的流畅接口
      • 使用指挥者角色
    • 建造者模式的应用场景
      • 复杂对象的创建
      • 参数众多的构造函数
      • 不同表示的构建过程
    • 建造者模式的优缺点
      • 优点
      • 缺点
    • 总结
    • 相关学习资源

建造者模式定义

建造者模式(Builder Pattern)的定义是:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示

建造者模式属于创建型设计模式,它解决的核心问题包括:

  • 如何构建一个由多个部分组成的复杂对象
  • 如何避免"伸缩式构造函数"的问题
  • 如何允许对象有不同的表示形式
  • 如何分离对象的构建和表示

建造者模式的UML类图

以下是建造者模式的UML类图:

directs
creates
creates
Director
Construct(builder: Builder)
Builder
BuildPartA()
BuildPartB()
BuildPartC()
GetResult()
ConcreteBuilder1
product: Product
BuildPartA()
BuildPartB()
BuildPartC()
GetResult()
ConcreteBuilder2
product: Product
BuildPartA()
BuildPartB()
BuildPartC()
GetResult()
Product
partA: string
partB: string
partC: string
Show()

建造者模式的组成部分

建造者模式包含以下几个核心组件:

  1. 产品(Product)

    • 被构建的复杂对象
    • 包含多个组成部分
    • 具体建造者创建该产品的内部表示并定义装配过程
  2. 抽象建造者(Builder)

    • 声明创建产品各个部分的抽象接口
    • 定义构建产品各个部分的方法
    • 声明返回产品的方法
  3. 具体建造者(Concrete Builder)

    • 实现抽象建造者的接口
    • 定义并跟踪它所创建的产品
    • 提供检索产品的方法
    • 实现构建产品各个部分的细节
  4. 指挥者(Director)

    • 构造一个使用Builder接口的对象
    • 指导构建过程的顺序
    • 隐藏产品是如何组装的细节

客户端代码通常会创建一个具体建造者对象,将其传递给指挥者,然后通过指挥者开始构建过程。当构建过程完成后,客户端从建造者中获取产品。

建造者模式的实现方式

下面通过C#代码示例展示建造者模式的几种实现方式。

基本实现

首先,让我们看一个食品订单系统的例子,实现不同类型的餐点组合:

/// <summary>
/// 产品类 - 表示餐点
/// </summary>
public class Meal
{
    // 餐点的各个组成部分
    public string MainCourse { get; set; }
    public string SideDish { get; set; }
    public string Drink { get; set; }
    public string Dessert { get; set; }
    
    /// <summary>
    /// 显示餐点的完整信息
    /// </summary>
    public void ShowMeal()
    {
        Console.WriteLine("餐点信息:");
        Console.WriteLine($"- 主菜: {MainCourse ?? "无"}");
        Console.WriteLine($"- 配菜: {SideDish ?? "无"}");
        Console.WriteLine($"- 饮料: {Drink ?? "无"}");
        Console.WriteLine($"- 甜点: {Dessert ?? "无"}");
    }
}

/// <summary>
/// 抽象建造者 - 定义创建餐点各部分的方法
/// </summary>
public interface IMealBuilder
{
    void BuildMainCourse();
    void BuildSideDish();
    void BuildDrink();
    void BuildDessert();
    Meal GetMeal();
}

/// <summary>
/// 具体建造者 - 健康餐点建造者
/// </summary>
public class HealthyMealBuilder : IMealBuilder
{
    private Meal _meal = new Meal();
    
    public void BuildMainCourse()
    {
        _meal.MainCourse = "烤鸡胸肉";
    }
    
    public void BuildSideDish()
    {
        _meal.SideDish = "蒸蔬菜";
    }
    
    public void BuildDrink()
    {
        _meal.Drink = "矿泉水";
    }
    
    public void BuildDessert()
    {
        _meal.Dessert = "水果沙拉";
    }
    
    public Meal GetMeal()
    {
        return _meal;
    }
}

/// <summary>
/// 具体建造者 - 快餐建造者
/// </summary>
public class FastFoodMealBuilder : IMealBuilder
{
    private Meal _meal = new Meal();
    
    public void BuildMainCourse()
    {
        _meal.MainCourse = "汉堡";
    }
    
    public void BuildSideDish()
    {
        _meal.SideDish = "炸薯条";
    }
    
    public void BuildDrink()
    {
        _meal.Drink = "可乐";
    }
    
    public void BuildDessert()
    {
        _meal.Dessert = "冰淇淋";
    }
    
    public Meal GetMeal()
    {
        return _meal;
    }
}

/// <summary>
/// 指挥者 - 负责构建过程
/// </summary>
public class MealDirector
{
    /// <summary>
    /// 构建完整餐点
    /// </summary>
    /// <param name="builder">餐点建造者</param>
    /// <returns>构建好的餐点</returns>
    public Meal ConstructFullMeal(IMealBuilder builder)
    {
        builder.BuildMainCourse();
        builder.BuildSideDish();
        builder.BuildDrink();
        builder.BuildDessert();
        return builder.GetMeal();
    }
    
    /// <summary>
    /// 构建没有甜点的餐点
    /// </summary>
    /// <param name="builder">餐点建造者</param>
    /// <returns>构建好的餐点</returns>
    public Meal ConstructMealWithoutDessert(IMealBuilder builder)
    {
        builder.BuildMainCourse();
        builder.BuildSideDish();
        builder.BuildDrink();
        return builder.GetMeal();
    }
}

/// <summary>
/// 客户端代码
/// </summary>
public class Client
{
    public static void Run()
    {
        // 创建指挥者
        var director = new MealDirector();
        
        // 使用健康餐点建造者
        var healthyBuilder = new HealthyMealBuilder();
        var healthyMeal = director.ConstructFullMeal(healthyBuilder);
        
        Console.WriteLine("健康餐点:");
        healthyMeal.ShowMeal();
        
        // 使用快餐建造者,不含甜点
        var fastFoodBuilder = new FastFoodMealBuilder();
        var fastFoodMeal = director.ConstructMealWithoutDessert(fastFoodBuilder);
        
        Console.WriteLine("\n快餐餐点(无甜点):");
        fastFoodMeal.ShowMeal();
    }
}

// 执行客户端代码
Client.Run();

/* 输出结果:
健康餐点:
餐点信息:
- 主菜: 烤鸡胸肉
- 配菜: 蒸蔬菜
- 饮料: 矿泉水
- 甜点: 水果沙拉

快餐餐点(无甜点):
餐点信息:
- 主菜: 汉堡
- 配菜: 炸薯条
- 饮料: 可乐
- 甜点: 无
*/

在这个基本实现中:

  • Meal 是被构建的产品
  • IMealBuilder 是抽象建造者,定义了构建餐点各部分的方法
  • HealthyMealBuilderFastFoodMealBuilder 是具体建造者,实现了不同风格的餐点创建
  • MealDirector 是指挥者,控制构建过程的顺序
  • 客户端可以选择不同的建造者来创建不同类型的餐点,以及选择不同的构建方式(完整或无甜点)

使用链式调用的流畅接口

建造者模式的一个常见变体是使用方法链(链式调用)创建流畅接口,这在C#中特别常见:

/// <summary>
/// 产品类 - 电子邮件
/// </summary>
public class Email
{
    // 电子邮件的各个组成部分
    public string From { get; set; }
    public string To { get; set; }
    public string Subject { get; set; }
    public string Body { get; set; }
    public List<string> Attachments { get; set; } = new List<string>();
    public bool IsHtml { get; set; }
    public string Cc { get; set; }
    public string Bcc { get; set; }
    
    /// <summary>
    /// 显示电子邮件的内容
    /// </summary>
    public void Display()
    {
        Console.WriteLine("电子邮件详情:");
        Console.WriteLine($"发件人: {From}");
        Console.WriteLine($"收件人: {To}");
        if (!string.IsNullOrEmpty(Cc)) Console.WriteLine($"抄送: {Cc}");
        if (!string.IsNullOrEmpty(Bcc)) Console.WriteLine($"密送: {Bcc}");
        Console.WriteLine($"主题: {Subject}");
        Console.WriteLine($"正文: {Body}");
        Console.WriteLine($"格式: {(IsHtml ? "HTML" : "纯文本")}");
        
        if (Attachments.Count > 0)
        {
            Console.WriteLine("附件:");
            foreach (var attachment in Attachments)
            {
                Console.WriteLine($"- {attachment}");
            }
        }
    }
}

/// <summary>
/// 流畅接口建造者 - 电子邮件建造者
/// </summary>
public class EmailBuilder
{
    private readonly Email _email = new Email();
    
    /// <summary>
    /// 设置发件人地址
    /// </summary>
    /// <param name="from">发件人邮箱地址</param>
    /// <returns>当前建造者实例以支持链式调用</returns>
    public EmailBuilder From(string from)
    {
        _email.From = from;
        return this;
    }
    
    /// <summary>
    /// 设置收件人地址
    /// </summary>
    /// <param name="to">收件人邮箱地址</param>
    /// <returns>当前建造者实例以支持链式调用</returns>
    public EmailBuilder To(string to)
    {
        _email.To = to;
        return this;
    }
    
    /// <summary>
    /// 设置邮件主题
    /// </summary>
    /// <param name="subject">邮件主题</param>
    /// <returns>当前建造者实例以支持链式调用</returns>
    public EmailBuilder WithSubject(string subject)
    {
        _email.Subject = subject;
        return this;
    }
    
    /// <summary>
    /// 设置邮件正文内容
    /// </summary>
    /// <param name="body">邮件内容</param>
    /// <returns>当前建造者实例以支持链式调用</returns>
    public EmailBuilder WithBody(string body)
    {
        _email.Body = body;
        return this;
    }
    
    /// <summary>
    /// 添加附件
    /// </summary>
    /// <param name="attachment">附件路径</param>
    /// <returns>当前建造者实例以支持链式调用</returns>
    public EmailBuilder WithAttachment(string attachment)
    {
        _email.Attachments.Add(attachment);
        return this;
    }
    
    /// <summary>
    /// 设置邮件为HTML格式
    /// </summary>
    /// <param name="isHtml">是否是HTML格式</param>
    /// <returns>当前建造者实例以支持链式调用</returns>
    public EmailBuilder AsHtml(bool isHtml = true)
    {
        _email.IsHtml = isHtml;
        return this;
    }
    
    /// <summary>
    /// 设置抄送地址
    /// </summary>
    /// <param name="cc">抄送邮箱地址</param>
    /// <returns>当前建造者实例以支持链式调用</returns>
    public EmailBuilder WithCc(string cc)
    {
        _email.Cc = cc;
        return this;
    }
    
    /// <summary>
    /// 设置密送地址
    /// </summary>
    /// <param name="bcc">密送邮箱地址</param>
    /// <returns>当前建造者实例以支持链式调用</returns>
    public EmailBuilder WithBcc(string bcc)
    {
        _email.Bcc = bcc;
        return this;
    }
    
    /// <summary>
    /// 构建电子邮件对象
    /// </summary>
    /// <returns>构建好的电子邮件</returns>
    public Email Build()
    {
        // 这里可以添加验证逻辑,例如检查必填字段
        if (string.IsNullOrEmpty(_email.From))
            throw new InvalidOperationException("发件人地址不能为空");
            
        if (string.IsNullOrEmpty(_email.To))
            throw new InvalidOperationException("收件人地址不能为空");
            
        return _email;
    }
}

// 客户端代码
public class FluentClient
{
    public static void Run()
    {
        // 使用流畅接口创建一封简单邮件
        var simpleEmail = new EmailBuilder()
            .From("sender@example.com")
            .To("recipient@example.com")
            .WithSubject("问候邮件")
            .WithBody("您好!这是一封测试邮件。")
            .Build();
            
        Console.WriteLine("简单邮件:");
        simpleEmail.Display();
        
        // 使用流畅接口创建一封复杂邮件
        var complexEmail = new EmailBuilder()
            .From("manager@company.com")
            .To("team@company.com")
            .WithCc("supervisor@company.com")
            .WithBcc("records@company.com")
            .WithSubject("项目进度报告")
            .WithBody("<h1>项目进度</h1><p>团队成员们,请查看附件中的项目进度报告。</p>")
            .AsHtml()
            .WithAttachment("progress_report.pdf")
            .WithAttachment("schedule.xlsx")
            .Build();
            
        Console.WriteLine("\n复杂邮件:");
        complexEmail.Display();
    }
}

// 执行客户端代码
FluentClient.Run();

/* 输出结果:
简单邮件:
电子邮件详情:
发件人: sender@example.com
收件人: recipient@example.com
主题: 问候邮件
正文: 您好!这是一封测试邮件。
格式: 纯文本

复杂邮件:
电子邮件详情:
发件人: manager@company.com
收件人: team@company.com
抄送: supervisor@company.com
密送: records@company.com
主题: 项目进度报告
正文: <h1>项目进度</h1><p>团队成员们,请查看附件中的项目进度报告。</p>
格式: HTML
附件:
- progress_report.pdf
- schedule.xlsx
*/

在这个流畅接口实现中:

  • 每个设置方法返回建造者本身,这使得可以链式调用方法
  • 提供了一种更加简洁、可读性更高的方式来构建复杂对象
  • 允许按需设置各个属性,支持可选参数
  • 在最后调用Build()方法来获取构建好的对象,同时可以进行必要的验证

使用指挥者角色

在一些更复杂的场景中,指挥者(Director)角色可以更好地封装不同的构建过程。下面是一个使用指挥者角色的计算机配置示例:

/// <summary>
/// 产品类 - 计算机
/// </summary>
public class Computer
{
    // 计算机的各个组件
    public string CPU { get; set; }
    public string RAM { get; set; }
    public string Storage { get; set; }
    public string GraphicsCard { get; set; }
    public string Monitor { get; set; }
    public string OperatingSystem { get; set; }
    
    /// <summary>
    /// 显示计算机配置
    /// </summary>
    public void ShowConfiguration()
    {
        Console.WriteLine("计算机配置:");
        Console.WriteLine($"CPU: {CPU ?? "未指定"}");
        Console.WriteLine($"内存: {RAM ?? "未指定"}");
        Console.WriteLine($"存储: {Storage ?? "未指定"}");
        Console.WriteLine($"显卡: {GraphicsCard ?? "未指定"}");
        Console.WriteLine($"显示器: {Monitor ?? "未指定"}");
        Console.WriteLine($"操作系统: {OperatingSystem ?? "未指定"}");
    }
}

/// <summary>
/// 抽象建造者 - 计算机建造者
/// </summary>
public interface IComputerBuilder
{
    void BuildCPU();
    void BuildRAM();
    void BuildStorage();
    void BuildGraphicsCard();
    void BuildMonitor();
    void InstallOperatingSystem();
    Computer GetComputer();
}

/// <summary>
/// 具体建造者 - 游戏计算机建造者
/// </summary>
public class GamingComputerBuilder : IComputerBuilder
{
    private Computer _computer = new Computer();
    
    public void BuildCPU()
    {
        _computer.CPU = "Intel Core i9-11900K";
    }
    
    public void BuildRAM()
    {
        _computer.RAM = "32GB DDR4 3600MHz";
    }
    
    public void BuildStorage()
    {
        _computer.Storage = "2TB NVMe SSD";
    }
    
    public void BuildGraphicsCard()
    {
        _computer.GraphicsCard = "NVIDIA GeForce RTX 3080";
    }
    
    public void BuildMonitor()
    {
        _computer.Monitor = "27英寸 4K 144Hz 游戏显示器";
    }
    
    public void InstallOperatingSystem()
    {
        _computer.OperatingSystem = "Windows 11 Pro";
    }
    
    public Computer GetComputer()
    {
        return _computer;
    }
}

/// <summary>
/// 具体建造者 - 办公计算机建造者
/// </summary>
public class OfficeComputerBuilder : IComputerBuilder
{
    private Computer _computer = new Computer();
    
    public void BuildCPU()
    {
        _computer.CPU = "Intel Core i5-11400";
    }
    
    public void BuildRAM()
    {
        _computer.RAM = "16GB DDR4 2666MHz";
    }
    
    public void BuildStorage()
    {
        _computer.Storage = "512GB SSD";
    }
    
    public void BuildGraphicsCard()
    {
        _computer.GraphicsCard = "集成显卡";
    }
    
    public void BuildMonitor()
    {
        _computer.Monitor = "24英寸 1080p 办公显示器";
    }
    
    public void InstallOperatingSystem()
    {
        _computer.OperatingSystem = "Windows 10 专业版";
    }
    
    public Computer GetComputer()
    {
        return _computer;
    }
}

/// <summary>
/// 具体建造者 - 开发计算机建造者
/// </summary>
public class DeveloperComputerBuilder : IComputerBuilder
{
    private Computer _computer = new Computer();
    
    public void BuildCPU()
    {
        _computer.CPU = "AMD Ryzen 9 5900X";
    }
    
    public void BuildRAM()
    {
        _computer.RAM = "64GB DDR4 3200MHz";
    }
    
    public void BuildStorage()
    {
        _computer.Storage = "1TB NVMe SSD + 2TB HDD";
    }
    
    public void BuildGraphicsCard()
    {
        _computer.GraphicsCard = "NVIDIA GeForce RTX 3060";
    }
    
    public void BuildMonitor()
    {
        _computer.Monitor = "双 27英寸 4K 专业显示器";
    }
    
    public void InstallOperatingSystem()
    {
        _computer.OperatingSystem = "Ubuntu 22.04 LTS";
    }
    
    public Computer GetComputer()
    {
        return _computer;
    }
}

/// <summary>
/// 指挥者 - 计算机装配指挥者
/// </summary>
public class ComputerDirector
{
    /// <summary>
    /// 构建完整计算机
    /// </summary>
    /// <param name="builder">计算机建造者</param>
    /// <returns>构建好的计算机</returns>
    public Computer BuildFullComputer(IComputerBuilder builder)
    {
        builder.BuildCPU();
        builder.BuildRAM();
        builder.BuildStorage();
        builder.BuildGraphicsCard();
        builder.BuildMonitor();
        builder.InstallOperatingSystem();
        return builder.GetComputer();
    }
    
    /// <summary>
    /// 构建基本计算机(无显卡、基本显示器)
    /// </summary>
    /// <param name="builder">计算机建造者</param>
    /// <returns>构建好的计算机</returns>
    public Computer BuildBasicComputer(IComputerBuilder builder)
    {
        builder.BuildCPU();
        builder.BuildRAM();
        builder.BuildStorage();
        builder.InstallOperatingSystem();
        return builder.GetComputer();
    }
    
    /// <summary>
    /// 构建无操作系统的计算机
    /// </summary>
    /// <param name="builder">计算机建造者</param>
    /// <returns>构建好的计算机</returns>
    public Computer BuildComputerWithoutOS(IComputerBuilder builder)
    {
        builder.BuildCPU();
        builder.BuildRAM();
        builder.BuildStorage();
        builder.BuildGraphicsCard();
        builder.BuildMonitor();
        return builder.GetComputer();
    }
}

/// <summary>
/// 客户端代码
/// </summary>
public class DirectorClient
{
    public static void Run()
    {
        // 创建指挥者
        var director = new ComputerDirector();
        
        // 构建游戏计算机(完整配置)
        var gamingBuilder = new GamingComputerBuilder();
        var gamingComputer = director.BuildFullComputer(gamingBuilder);
        
        Console.WriteLine("游戏计算机配置:");
        gamingComputer.ShowConfiguration();
        
        // 构建基本办公计算机
        var officeBuilder = new OfficeComputerBuilder();
        var officeComputer = director.BuildBasicComputer(officeBuilder);
        
        Console.WriteLine("\n办公计算机配置:");
        officeComputer.ShowConfiguration();
        
        // 构建无操作系统的开发计算机
        var developerBuilder = new DeveloperComputerBuilder();
        var developerComputer = director.BuildComputerWithoutOS(developerBuilder);
        
        Console.WriteLine("\n开发计算机配置(无操作系统):");
        developerComputer.ShowConfiguration();
    }
}

// 执行客户端代码
DirectorClient.Run();

/* 输出结果:
游戏计算机配置:
计算机配置:
CPU: Intel Core i9-11900K
内存: 32GB DDR4 3600MHz
存储: 2TB NVMe SSD
显卡: NVIDIA GeForce RTX 3080
显示器: 27英寸 4K 144Hz 游戏显示器
操作系统: Windows 11 Pro

办公计算机配置:
计算机配置:
CPU: Intel Core i5-11400
内存: 16GB DDR4 2666MHz
存储: 512GB SSD
显卡: 未指定
显示器: 未指定
操作系统: Windows 10 专业版

开发计算机配置(无操作系统):
计算机配置:
CPU: AMD Ryzen 9 5900X
内存: 64GB DDR4 3200MHz
存储: 1TB NVMe SSD + 2TB HDD
显卡: NVIDIA GeForce RTX 3060
显示器: 双 27英寸 4K 专业显示器
操作系统: 未指定
*/

在这个实现中:

  • 指挥者(ComputerDirector)定义了多种不同的构建过程(完整、基本、无操作系统)
  • 具体建造者(GamingComputerBuilderOfficeComputerBuilderDeveloperComputerBuilder)提供了不同的实现方式
  • 客户端可以选择不同的建造者和构建过程的组合,以获得不同配置的计算机
  • 指挥者封装了构建过程,使得客户端代码更加简洁

建造者模式的应用场景

建造者模式适用于以下场景:

建造者模式应用场景
复杂对象的创建
参数众多的构造函数
不同表示的构建过程
分步构建对象
不变性对象的创建

复杂对象的创建

当对象包含多个部分,或者构建需要多个步骤时,建造者模式能够提供清晰的创建过程:

  • 文档生成器(如HTML、PDF、Word文档)
  • 复杂的图形用户界面构建
  • 配置对象的创建
  • 复杂的数据转换和导出

参数众多的构造函数

在需要处理大量可选参数时,建造者模式可以避免"伸缩式构造函数"问题:

  • 避免了使用多个重载构造函数
  • 避免了使用大量参数的构造函数
  • 允许仅设置需要的参数
  • 代码可读性和可维护性更高

不同表示的构建过程

当同一个构建过程可以创建不同表示的对象时,建造者模式特别有用:

  • 不同格式的报告生成
  • 不同风格的UI组件创建
  • 不同平台的代码生成器

建造者模式的优缺点

优点

  1. 分离构建和表示:建造者模式将对象的构建过程与其表示分离,使得同样的构建过程可以创建不同的表示。

  2. 封装变化:产品的内部结构可以变化,而不会影响客户端代码,因为客户端只与抽象接口交互。

  3. 更好的控制构建过程:建造者模式允许对对象的构建过程进行更精细的控制,特别是在复杂对象的构建中。

  4. 隐藏产品的内部结构:产品的具体细节对客户端是不可见的,客户端只需要与建造者交互。

  5. 提高代码可读性:特别是在使用流畅接口时,构建过程清晰易读。

缺点

  1. 增加类的数量:建造者模式引入了多个新的类,这可能增加系统的复杂性。

  2. 与特定类型绑定:每个具体建造者与特定的产品类型绑定,限制了灵活性。

  3. 不适合简单对象:对于简单对象,使用建造者模式可能是过度设计。

  4. 指挥者可能不总是必要的:在一些实现中,特别是使用流畅接口时,指挥者角色可能是多余的。

  5. 可能导致代码重复:不同的具体建造者可能包含相似的代码。

总结

建造者模式是一种功能强大的创建型设计模式,它允许我们分步骤创建复杂对象,并且可以使用相同的构建过程创建不同的表示。这种模式特别适合处理具有多个组成部分或需要复杂构建过程的对象。

在C#中,建造者模式有多种实现方式,从传统的实现(使用抽象建造者、具体建造者和指挥者),到更现代的流畅接口实现。流畅接口特别适合C#,它提供了一种简洁、可读性强的方式来构建对象。

建造者模式与其他创建型模式(如工厂方法和抽象工厂)相比,更加关注对象的分步构建过程,而不仅仅是简单的实例化。它为控制复杂对象的创建过程提供了更细粒度的方法。

虽然建造者模式增加了代码的复杂性,但在处理复杂对象创建、避免构造函数参数过多或需要不同表示的场景中,这种复杂性是值得的。通过合理应用建造者模式,我们可以创建更加灵活、可维护和可扩展的代码。

相关学习资源

网站资源:

  • Refactoring Guru - Builder Pattern
  • Microsoft Learn - Design Patterns
  • SourceMaking - Builder Design Pattern
  • C# Corner - Builder Design Pattern in C#
  • Dofactory - .NET Design Pattern Framework - Builder

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2397905.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

现场总线结构在楼宇自控系统中的技术要求与实施要点分析

在建筑智能化程度不断提升的当下&#xff0c;楼宇自控系统承担着协调建筑内各类设备高效运行的重任。传统的集中式控制系统在面对复杂建筑环境时&#xff0c;逐渐暴露出布线繁琐、扩展性差、可靠性低等问题。而现场总线结构凭借其分散控制、通信高效等特性&#xff0c;成为楼宇…

学习路之PHP--easyswoole使用视图和模板

学习路之PHP--easyswoole使用视图和模板 一、安装依赖插件二、 实现渲染引擎三、注册渲染引擎四、测试调用写的模板五、优化六、最后补充 一、安装依赖插件 composer require easyswoole/template:1.1.* composer require topthink/think-template相关版本&#xff1a; "…

《云原生安全攻防》-- K8s网络策略:通过NetworkPolicy实现微隔离

默认情况下&#xff0c;K8s集群的网络是没有任何限制的&#xff0c;所有的Pod之间都可以相互访问。这就意味着&#xff0c;一旦攻击者入侵了某个Pod&#xff0c;就能够访问到集群中任意Pod&#xff0c;存在比较大的安全风险。 在本节课程中&#xff0c;我们将详细介绍如何通过N…

06 APP 自动化- H5 元素定位

文章目录 H5 元素定位1、APP 分类2、H5 元素3、H5 元素定位环境的搭建4、代码实现&#xff1a; H5 元素定位 1、APP 分类 1、Android 原生 APP2、混合 APP(Android 原生控件H5页面)3、纯 H5 App 2、H5 元素 H5 元素容器 WebViewWebView 控件实现展示网页 3、H5 元素定位环…

定时线程池失效问题引发的思考

最近在做的一个新功能&#xff0c;在结果探测的时候使用了定时线程池和普通线程池结合&#xff0c;定时线程池周期性创建子任务并往普通线程池提交任务。 问题&#xff1a; 在昨天测试老师发现&#xff0c;业务实际上已经成功了&#xff0c;但是页面还是一直显示进行中。 收到…

AXURE安装+汉化-Windows

安装网站&#xff1a;https://www.axure.com/release-history/rp9 Axure中文汉化包下载地址 链接:https://pan.baidu.com/s/1U62Azk8lkRPBqWAcrJMFew?pwd5418 提取码:5418 下载完成之后&#xff0c;crtlc lang文件夹 到下载的Axure路径下 双击点进这个目录里面。ctrlv把lan…

ArcGIS Pro字段计算器与计算几何不可用,显示灰色

“字段计算器”不可用 如果计算字段命令不可用&#xff0c;请考虑以下可能性&#xff1a; 由 ArcGIS 管理的字段无法手动编辑。因此&#xff0c;无法计算 ObjectID&#xff08;OID 或 FID&#xff09;字段或地理数据库要素类的 Shape_Length 和 Shape_Area 字段的字段值。表中…

mac电脑安装 nvm 报错如何解决

前言 已知&#xff1a;安装nvm成功&#xff1b;终端输入nvm -v 有版本返回 1. 启动全局配置环境变量失败 source ~/.zshrc~ 返回&#xff1a; source: no such file or directory: /Users/你的用户名/.zshrc~2 安装node失败 nvm install 16.13返回&#xff1a; mkdir: /U…

第11节 Node.js 模块系统

为了让Node.js的文件可以相互调用&#xff0c;Node.js提供了一个简单的模块系统。 模块是Node.js 应用程序的基本组成部分&#xff0c;文件和模块是一一对应的。换言之&#xff0c;一个 Node.js 文件就是一个模块&#xff0c;这个文件可能是JavaScript 代码、JSON 或者编译过的…

上海工作机会:Technical Writer Senior Technical Writer - 中微半导体设备

大名鼎鼎的中微半导体招聘文档工程师了&#xff0c;就是那家由中国半导体产业的领军人物尹志尧领导的、全员持股的公司。如果你还不了解他&#xff0c;赶快Deepseek一下“尹志尧”了解。 招聘职位&#xff1a;Technical Writer & Senior Technical Writer 公司名称&#…

Python微积分可视化:从导数到积分的交互式教学工具

Python微积分可视化:从导数到积分的交互式教学工具 一、引言 微积分是理解自然科学的基础,但抽象的导数、积分概念常让初学者感到困惑。本文基于Matplotlib开发一套微积分可视化工具,通过动态图像直观展示导数的几何意义、积分的近似计算及跨学科应用,帮助读者建立"数…

Juce实现Table自定义

Juce实现Table自定义 一.总体展示概及概述 在项目中Juce中TableList往往无法满足用户需求&#xff0c;头部和背景及背景颜色设置以及在Cell中添加自定义按钮&#xff0c;所以需要自己实现自定义TabelList&#xff0c;该示例是展示实现自定义TableList&#xff0c;实现自定义标…

【后端高阶面经:架构篇】51、搜索引擎架构与排序算法:面试关键知识点全解析

一、搜索引擎核心基石&#xff1a;倒排索引技术深度解析 &#xff08;一&#xff09;倒排索引的本质与构建流程 倒排索引&#xff08;Inverted Index&#xff09;是搜索引擎实现快速检索的核心数据结构&#xff0c;与传统数据库的正向索引&#xff08;文档→关键词&#xff0…

Windows应用-音视频捕获

下载“Windows应用-音视频捕获”项目 本应用可以同时捕获4个视频源和4个音频源&#xff0c;可以监视视频源图像&#xff0c;监听音频源&#xff1b;可以将视频源图像写入MP4文件&#xff0c;将音频源写入MP3或WAV文件&#xff1b;还可以录制系统播放的声音。本应用使用MFC对话框…

【OCCT+ImGUI系列】012-Geom2d_AxisPlacement

Geom2d_AxisPlacement 教学笔记 一、类概述 Geom2d_AxisPlacement 表示二维几何空间中的一个坐标轴&#xff08;轴系&#xff09;&#xff0c;由两部分组成&#xff1a; gp_Pnt2d&#xff1a;原点&#xff08;Location&#xff09;gp_Dir2d&#xff1a;单位方向向量&#xff…

【C++高并发内存池篇】性能卷王养成记:C++ 定长内存池,让内存分配快到飞起!

&#x1f4dd;本篇摘要 在本篇将介绍C定长内存池的概念及实现问题&#xff0c;引入内存池技术&#xff0c;通过实现一个简单的定长内存池部分&#xff0c;体会奥妙所在&#xff0c;进而为之后实现整体的内存池做铺垫&#xff01; &#x1f3e0;欢迎拜访&#x1f3e0;&#xff…

mac下通过anaconda安装Python

本次分享mac下通过anaconda安装Python、Jupyter Notebook、R。 anaconda安装 点击&#x1f449;https://www.anaconda.com/download&#xff0c; 点击Mac系统安装包&#xff0c; 选择Mac芯片&#xff1a;苹果芯片 or intel芯片&#xff0c; 选择苹果芯片图形界面安装&#x…

微软PowerBI考试 PL300-Power BI 入门

Power BI 入门 上篇更新了微软PowerBI考试 PL-300学习指南&#xff0c;今天分享PowerBI入门学习内容。 简介 Microsoft Power BI 是一个完整的报表解决方案&#xff0c;通过开发工具和联机平台提供数据准备、数据可视化、分发和管理。 Power BI 可以从使用单个数据源的简单…

逻辑回归知识点

一、逻辑回归概念 逻辑回归(Logistic Regression)是一种广泛应用于分类问题的统计方法&#xff0c;尤其适用于二分类问题。 注意: 尽管名称中有"回归"二字&#xff0c;但它实际上是一种分类算法。 解决二分类的问题。 API&#xff1a;sklearn.linear_model.Logis…

Ubuntu22.04 安装 CUDA12.8

1.下载CUDA 由于我装完 Ubuntu22.04 后就自动带了最新的显卡驱动&#xff0c;就没有再去配置驱动。 先查看驱动能支持的CUDA最高版本&#xff0c;这里显示可支持到12.8。 nvidia-smi在CUDA的 说明文档 可查看CUDA对应的驱动版本要求。 在 CUDA Toolkit Archive 查找需要的 …