C# 设计模式--建造者模式 (Builder Pattern)

定义

建造者模式是一种创建型设计模式,它允许你逐步构建复杂对象,而无需使用多个构造函数或重载。建造者模式将对象的构建过程与表示分离,使得相同的构建过程可以创建不同的表示。

正确写法

假设我们有一个复杂的 Car 对象,需要逐步构建其各个部分(如引擎、轮胎、颜色等)。

csharp 复制代码
// 产品类
public class Car
{
    public string Engine { get; set; }
    public string Tires { get; set; }
    public string Color { get; set; }

    public override string ToString()
    {
        return $"Car: Engine={Engine}, Tires={Tires}, Color={Color}";
    }
}

// 抽象建造者
public abstract class CarBuilder
{
    protected Car car;

    public Car GetCar() => car;

    public abstract void BuildEngine();
    public abstract void BuildTires();
    public abstract void BuildColor();
}

// 具体建造者
public class SportsCarBuilder : CarBuilder
{
    public SportsCarBuilder()
    {
        car = new Car();
    }

    public override void BuildEngine() => car.Engine = "V8";
    public override void BuildTires() => car.Tires = "High-performance tires";
    public override void BuildColor() => car.Color = "Red";
}

public class LuxuryCarBuilder : CarBuilder
{
    public LuxuryCarBuilder()
    {
        car = new Car();
    }

    public override void BuildEngine() => car.Engine = "V6";
    public override void BuildTires() => car.Tires = "All-season tires";
    public override void BuildColor() => car.Color = "Black";
}

// 导演类
public class Director
{
    public void Construct(CarBuilder builder)
    {
        builder.BuildEngine();
        builder.BuildTires();
        builder.BuildColor();
    }
}

// 客户端代码
class Program
{
    static void Main(string[] args)
    {
        Director director = new Director();

        CarBuilder sportsCarBuilder = new SportsCarBuilder();
        director.Construct(sportsCarBuilder);
        Car sportsCar = sportsCarBuilder.GetCar();
        Console.WriteLine(sportsCar);

        CarBuilder luxuryCarBuilder = new LuxuryCarBuilder();
        director.Construct(luxuryCarBuilder);
        Car luxuryCar = luxuryCarBuilder.GetCar();
        Console.WriteLine(luxuryCar);
    }
}

类图:

Car -string Engine -string Tires -string Color +override string ToString() CarBuilder -Car car +Car GetCar() +abstract void BuildEngine() +abstract void BuildTires() +abstract void BuildColor() SportsCarBuilder +SportsCarBuilder() +override void BuildEngine() +override void BuildTires() +override void BuildColor() LuxuryCarBuilder +LuxuryCarBuilder() +override void BuildEngine() +override void BuildTires() +override void BuildColor() Director +void Construct(CarBuilder builder) Program +static void Main(string[] args)

解释

  1. 产品类 (Car):定义了汽车的属性(引擎、轮胎、颜色)和一个重写的 ToString 方法,用于显示汽车的详细信息。
  2. 抽象建造者 (CarBuilder):定义了一个受保护的 Car 对象,并提供了获取汽车的方法 GetCar 以及三个抽象方法 BuildEngineBuildTiresBuildColor
  3. 具体建造者 (SportsCarBuilderLuxuryCarBuilder):继承自 CarBuilder,具体实现了构建汽车各个部分的方法。
  4. 导演类 (Director):负责调用具体建造者的构建方法,按照一定的顺序构建汽车。
  5. 客户端代码 (Program):创建了 Director 对象和具体的建造者对象,通过导演类的 Construct 方法构建汽车,并最终获取和显示汽车的信息。

用途

  1. 逐步构建复杂对象:当对象的构建过程复杂且需要多个步骤时,使用建造者模式可以将构建过程分解为多个方法调用。
  2. 分离构建过程和表示:建造者模式将对象的构建过程与表示分离,使得相同的构建过程可以创建不同的表示。
  3. 避免大量的构造函数:避免使用多个构造函数或重载,使代码更加清晰和易于维护。

优点

  1. 封装性好:将对象的构建过程封装在建造者类中,客户端代码不需要关心具体的构建细节。
  2. 代码复用性高:相同的构建过程可以创建不同的表示,提高了代码的复用性。
  3. 易于扩展:增加新的建造者类时,不需要修改现有的代码,符合开闭原则。

缺点

  1. 代码复杂度增加:引入了多个类(抽象建造者、具体建造者、导演类等),系统结构变得更复杂。
  2. 增加类的数量:每增加一个新的产品类型,就需要增加相应的建造者类,类的数量会增加。
  3. 灵活性受限:如果产品的内部表示发生变化,可能需要修改多个建造者类。
    适用场景
  4. 对象构建过程复杂:当对象的构建过程复杂且需要多个步骤时。
  5. 对象的表示多种多样:当需要创建多种不同表示的对象时。
  6. 避免大量的构造函数:当对象的构造函数参数较多且复杂时。

实际开发中的应用

1. 配置文件解析

假设我们需要解析一个复杂的配置文件,并根据配置文件的内容创建相应的对象。

代码如下:

csharp 复制代码
// 配置对象
public class Configuration
{
    public string Host { get; set; }
    public int Port { get; set; }
    public string Username { get; set; }
    public string Password { get; set; }

    public override string ToString()
    {
        return $"Configuration: Host={Host}, Port={Port}, Username={Username}, Password={Password}";
    }
}

// 抽象建造者
public abstract class ConfigurationBuilder
{
    protected Configuration configuration;

    public Configuration GetConfiguration() => configuration;

    public abstract void BuildHost();
    public abstract void BuildPort();
    public abstract void BuildUsername();
    public abstract void BuildPassword();
}

// 具体建造者
public class ProductionConfigBuilder : ConfigurationBuilder
{
    public ProductionConfigBuilder()
    {
        configuration = new Configuration();
    }

    public override void BuildHost() => configuration.Host = "prod.example.com";
    public override void BuildPort() => configuration.Port = 8080;
    public override void BuildUsername() => configuration.Username = "admin";
    public override void BuildPassword() => configuration.Password = "securepassword";
}

public class DevelopmentConfigBuilder : ConfigurationBuilder
{
    public DevelopmentConfigBuilder()
    {
        configuration = new Configuration();
    }

    public override void BuildHost() => configuration.Host = "dev.example.com";
    public override void BuildPort() => configuration.Port = 8081;
    public override void BuildUsername() => configuration.Username = "devuser";
    public override void BuildPassword() => configuration.Password = "devpassword";
}

// 导演类
public class ConfigDirector
{
    public void Construct(ConfigurationBuilder builder)
    {
        builder.BuildHost();
        builder.BuildPort();
        builder.BuildUsername();
        builder.BuildPassword();
    }
}

// 客户端代码
class Program
{
    static void Main(string[] args)
    {
        ConfigDirector director = new ConfigDirector();

        ConfigurationBuilder productionBuilder = new ProductionConfigBuilder();
        director.Construct(productionBuilder);
        Configuration productionConfig = productionBuilder.GetConfiguration();
        Console.WriteLine(productionConfig);

        ConfigurationBuilder developmentBuilder = new DevelopmentConfigBuilder();
        director.Construct(developmentBuilder);
        Configuration developmentConfig = developmentBuilder.GetConfiguration();
        Console.WriteLine(developmentConfig);
    }
}

2. 报告生成

假设我们需要生成不同类型的报告(如 PDF 报告和 HTML 报告),并逐步构建报告的内容。

csharp 复制代码
// 报告对象
public class Report
{
    public string Title { get; set; }
    public string Content { get; set; }
    public string Footer { get; set; }

    public override string ToString()
    {
        return $"Report: Title={Title}, Content={Content}, Footer={Footer}";
    }
}

// 抽象建造者
public abstract class ReportBuilder
{
    protected Report report;

    public Report GetReport() => report;

    public abstract void BuildTitle();
    public abstract void BuildContent();
    public abstract void BuildFooter();
}

// 具体建造者
public class PdfReportBuilder : ReportBuilder
{
    public PdfReportBuilder()
    {
        report = new Report();
    }

    public override void BuildTitle() => report.Title = "PDF Report Title";
    public override void BuildContent() => report.Content = "This is the content of the PDF report.";
    public override void BuildFooter() => report.Footer = "Generated by PDF Report Builder";
}

public class HtmlReportBuilder : ReportBuilder
{
    public HtmlReportBuilder()
    {
        report = new Report();
    }

    public override void BuildTitle() => report.Title = "HTML Report Title";
    public override void BuildContent() => report.Content = "This is the content of the HTML report.";
    public override void BuildFooter() => report.Footer = "Generated by HTML Report Builder";
}

// 导演类
public class ReportDirector
{
    public void Construct(ReportBuilder builder)
    {
        builder.BuildTitle();
        builder.BuildContent();
        builder.BuildFooter();
    }
}

// 客户端代码
class Program
{
    static void Main(string[] args)
    {
        ReportDirector director = new ReportDirector();

        ReportBuilder pdfBuilder = new PdfReportBuilder();
        director.Construct(pdfBuilder);
        Report pdfReport = pdfBuilder.GetReport();
        Console.WriteLine(pdfReport);

        ReportBuilder htmlBuilder = new HtmlReportBuilder();
        director.Construct(htmlBuilder);
        Report htmlReport = htmlBuilder.GetReport();
        Console.WriteLine(htmlReport);
    }
}

总结

建造者模式 通过将对象的构建过程分解为多个方法调用,使得对象的创建更加灵活和可控。虽然它增加了系统的复杂度,但在需要逐步构建复杂对象的场景中,建造者模式能够显著提高代码的可维护性和扩展性。

在我看来,切碎一点,繁琐一点,微操大神,优势在我

相关推荐
NorthCastle3 小时前
设计模式-创建型模式-简单工厂模式详解
设计模式·简单工厂模式
向宇it5 小时前
【从零开始入门unity游戏开发之——C#篇23】C#面向对象继承——`as`类型转化和`is`类型检查、向上转型和向下转型、里氏替换原则(LSP)
java·开发语言·unity·c#·游戏引擎·里氏替换原则
越甲八千5 小时前
重拾设计模式-外观模式和适配器模式的异同
设计模式·适配器模式·外观模式
越甲八千5 小时前
重拾设计模式--适配器模式
设计模式·适配器模式
sukalot5 小时前
windows C#-命名实参和可选实参(下)
windows·c#
小码编匠5 小时前
.NET 下 RabbitMQ 队列、死信队列、延时队列及小应用
后端·c#·.net
越甲八千10 小时前
重拾设计模式--外观模式
c++·设计模式·外观模式
西岭千秋雪_11 小时前
设计模式の享元&模板&代理模式
java·设计模式·代理模式·享元模式·模板方法模式
越甲八千11 小时前
重撸设计模式--代理模式
设计模式·代理模式
越甲八千14 小时前
重拾设计模式--状态模式
c++·设计模式