定义
建造者模式是一种创建型设计模式,它允许你逐步构建复杂对象,而无需使用多个构造函数或重载。建造者模式将对象的构建过程与表示分离,使得相同的构建过程可以创建不同的表示。
正确写法
假设我们有一个复杂的 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)
解释
- 产品类 (Car):定义了汽车的属性(引擎、轮胎、颜色)和一个重写的 ToString 方法,用于显示汽车的详细信息。
- 抽象建造者 (
CarBuilder
):定义了一个受保护的Car
对象,并提供了获取汽车的方法GetCar
以及三个抽象方法BuildEngine
、BuildTires
和BuildColor
。 - 具体建造者 (
SportsCarBuilder
和LuxuryCarBuilder
):继承自CarBuilder
,具体实现了构建汽车各个部分的方法。 - 导演类 (
Director
):负责调用具体建造者的构建方法,按照一定的顺序构建汽车。 - 客户端代码 (
Program
):创建了Director
对象和具体的建造者对象,通过导演类的Construct
方法构建汽车,并最终获取和显示汽车的信息。
用途
- 逐步构建复杂对象:当对象的构建过程复杂且需要多个步骤时,使用建造者模式可以将构建过程分解为多个方法调用。
- 分离构建过程和表示:建造者模式将对象的构建过程与表示分离,使得相同的构建过程可以创建不同的表示。
- 避免大量的构造函数:避免使用多个构造函数或重载,使代码更加清晰和易于维护。
优点
- 封装性好:将对象的构建过程封装在建造者类中,客户端代码不需要关心具体的构建细节。
- 代码复用性高:相同的构建过程可以创建不同的表示,提高了代码的复用性。
- 易于扩展:增加新的建造者类时,不需要修改现有的代码,符合开闭原则。
缺点
- 代码复杂度增加:引入了多个类(抽象建造者、具体建造者、导演类等),系统结构变得更复杂。
- 增加类的数量:每增加一个新的产品类型,就需要增加相应的建造者类,类的数量会增加。
- 灵活性受限:如果产品的内部表示发生变化,可能需要修改多个建造者类。
适用场景 - 对象构建过程复杂:当对象的构建过程复杂且需要多个步骤时。
- 对象的表示多种多样:当需要创建多种不同表示的对象时。
- 避免大量的构造函数:当对象的构造函数参数较多且复杂时。
实际开发中的应用
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);
}
}
总结
建造者模式 通过将对象的构建过程分解为多个方法调用,使得对象的创建更加灵活和可控。虽然它增加了系统的复杂度,但在需要逐步构建复杂对象的场景中,建造者模式能够显著提高代码的可维护性和扩展性。
在我看来,切碎一点,繁琐一点,微操大神,优势在我