Builder 生成器模式简介与 C# 示例【创建型2】【设计模式来了_2】

builder,生成器,模式,简介,c#,示例,创建,设计模式 · 浏览次数 : 423

小编点评

**1、介绍** 介绍生成器模式和 Abstract Factory 模式,以及 Builder 和 AbstractFactory 模式之间的区别。 **2、生成器模式** 生成器模式侧重于一步步构造一个复杂的对象,并最终返回产品。 **3、Abstract Factory 模式** Abstract Factory 模式侧重于多个系列产品的产品对象(简单或复杂)。它在最后一步返回产品。 **4、Builder 模式** Builder 模式侧重于多个系列产品的产品对象,并最终返回产品。 Builder 在最后一步返回产品。 **5、Builder 和 AbstractFactory 模式之间的区别** Builder 模式侧重于一步步构造一个复杂的对象,而 Abstract Factory 模式侧重于多个系列产品的产品对象。 **6、构建过程** Builder 模式在最后一步返回产品,Abstract Factory 模式在最后一步返回产品。 **7、Composite 组合模式** Composite 组合模式是用 Builder 生成的。 **8、示例** 介绍 Builder 和 AbstractFactory 模式的示例,以及它们之间的区别。

正文

〇、简介

1、什么是生成器模式?

一句话解释:

  在构造一个复杂的对象(参数多且有可空类型)时,通过一个统一的构造链路,可选择的配置所需属性值,灵活实现可复用的构造过程。

生成器模式的重心,在于分离构建算法具体的构造实现,从而使得构建算法可以重用采用不同的构建实现,产生不同的产品。所以生成器模式都会存在两个部分:整体构建算法、部件的构造和产品的装配。

官方意图:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

一个比喻:(班级与各科课代表)

  每个班级都需要各科课代表,选人条件也会有多个,比如单科成绩名列前茅、课堂表现活跃等,还有些非必要的条件,例如是否开朗等,根据这些条件就可以制定一个标准,对应的就是统一的 IBuilder 接口。不同的科目都可以实现这个接口去生成自己的课代表。

2、优缺点和使用场景

优点:

  • 客户端不必知道目标对象内部组成的细节,目标对象本身与目标对象的创建过程解耦,使得相同的创建过程可以创建不同的目标对象;
  • 具体创建者可被扩展;
  • 更加精细化的操控目标对象的生成过程,根据生成器提供的步骤逐步构建,可以精细化的控制到产品的内部。

缺点:

  • 目标对象有很多共同特定,不同的目标对象组成类似,差异不是很多。

适用场景:

  • 当创建复杂对象的算法,应该独立于该对象的组成部分,以及它们的装配方式时。
  • 当构造过程必须允许被构造的对象有不同的表示时。

简言之:当一个类的构造函数参数个数超过4个,而且这些参数有些是可选的参数,考虑使用构造者模式。

一、简单的示例代码

 如下示例,通过生成器创建一个订单:

// 测试一下
public class Program
{
    static void Main(string[] args)
    {
        OrderBuilder builder = new OrderBuilder();
        OrderDirector director = new OrderDirector(builder);
        object order = director.Construct("John Doe", "Product ABC", 2, 10.99m);
        Console.WriteLine(order.ToString());
        Console.ReadLine();
    }
}
// 订单类
public class Order
{
    public string CustomerName { get; set; }
    public string ProductName { get; set; }
    public int Quantity { get; set; }
    public decimal TotalPrice { get; set; }
    public override string ToString() // 重写 ToString() 定义输出格式
    {
        return $"Customer: {CustomerName}\nProduct: {ProductName}\nQuantity: {Quantity}\nTotal Price: {TotalPrice}";
    }
}
// 生成器接口
public interface IBuilder
{
    OrderBuilder SetCustomer(string customerName);
    OrderBuilder AddProduct(string productName, int quantity, decimal price);
    Order Build();
}
// 订单生成器,实现接口 IBuilder
public class OrderBuilder : IBuilder
{
    private Order order;
    public OrderBuilder()
    {
        order = new Order();
    }
    public OrderBuilder SetCustomer(string customerName)
    {
        order.CustomerName = customerName;
        return this;
    }
    public OrderBuilder AddProduct(string productName, int quantity, decimal price)
    {
        order.ProductName = productName;
        order.Quantity = quantity;
        order.TotalPrice = quantity * price;
        return this;
    }
    public Order Build() // 最后返回创建的 Order 对象
    {
        return order;
    }
}
// 订单导向器,完成具体的构建步骤
public class OrderDirector
{
    private IBuilder builder;
    public OrderDirector(IBuilder builder)
    {
        this.builder = builder;
    }
    public Order Construct(string customerName, string productName, int quantity, decimal price)
    {
        builder.SetCustomer(customerName)
            .AddProduct(productName, quantity, price);
        return builder.Build();
    }
}

结果输出:

  

再试着扩展一下:(这里简单举个例子,线上和线下订单区别在是否有购买者用户名)

点击展开示例代码 线上线下订单生成
// 测试一下
public class Program
{
    static void Main(string[] args)
    {
        OnlineOrderBuilder onlinebuilder = new OnlineOrderBuilder();
        OrderDirector director_on = new OrderDirector(onlinebuilder);
        director_on.Construct(1, "AutoMation1", "Product ABC", 2, 10.99m, "John Doe");
        var order_on = onlinebuilder.Build();
        Console.WriteLine($"order_online-{order_on}");

        OfflineOrderBuilder offlinebuilder = new OfflineOrderBuilder();
        OrderDirector director_off = new OrderDirector(offlinebuilder);
        director_off.Construct(2, "AutoMation1", "Product 123", 2, 5.6m);
        var order_off = offlinebuilder.Build();
        Console.WriteLine($"order_offline-{order_off}");

        Console.ReadLine();
    }
}
// 生成器接口
public interface IBuilder
{
    IBuilder SetProductLine(string customerName);
    IBuilder AddProduct(string productName, int quantity, decimal price);
    IBuilder SetUsername(string username);
    object Build();
}
// 线上订单类
public class OnlineOrder
{
    public string ProductLine { get; set; }
    public string ProductName { get; set; }
    public int Quantity { get; set; }
    public decimal TotalPrice { get; set; }
    public string UserName { get; set; } // 区别就在于线上有用户名
    public override string ToString() // 重写 ToString() 定义输出格式
    {
        return $"OnlineOrder-ProductLine: {ProductLine}\nProduct: {ProductName}\nQuantity: {Quantity}\nTotal Price: {TotalPrice}\nUser Name: {UserName} \n";
    }
}
// 线上订单生成器,实现接口 IBuilder
public class OnlineOrderBuilder : IBuilder
{
    private OnlineOrder online_order;
    public OnlineOrderBuilder()
    {
        online_order = new OnlineOrder();
    }
    public IBuilder SetProductLine(string productline)
    {
        online_order.ProductLine = productline;
        return this;
    }
    public IBuilder AddProduct(string productName, int quantity, decimal price)
    {
        online_order.ProductName = productName;
        online_order.Quantity = quantity;
        online_order.TotalPrice = quantity * price;
        return this;
    }
    public IBuilder SetUsername(string username)
    {
        online_order.UserName = username;
        return this;
    }
    public object Build() // 最后返回创建的 Order 对象
    {
        return online_order;
    }
}
// 线下订单类
public class OfflineOrder
{
    public string ProductLine { get; set; }
    public string ProductName { get; set; }
    public int Quantity { get; set; }
    public decimal TotalPrice { get; set; }
    public override string ToString() // 重写 ToString() 定义输出格式
    {
        return $"OfflineOrder-ProductLine: {ProductLine}\nProduct: {ProductName}\nQuantity: {Quantity}\nTotal Price: {TotalPrice}";
    }
}
// 线下订单生成器,实现接口 IBuilder
public class OfflineOrderBuilder : IBuilder
{
    private OfflineOrder offline_order;
    public OfflineOrderBuilder()
    {
        offline_order = new OfflineOrder();
    }
    public IBuilder SetProductLine(string productline)
    {
        offline_order.ProductLine = productline;
        return this;
    }
    public IBuilder AddProduct(string productName, int quantity, decimal price)
    {
        offline_order.ProductName = productName;
        offline_order.Quantity = quantity;
        offline_order.TotalPrice = quantity * price;
        return this;
    }
    public IBuilder SetUsername(string username)
    {
        return this;
    }
    public object Build() // 最后返回创建的 Order 对象
    {
        return offline_order;
    }
}
// 订单导向器,完成具体的构建步骤
public class OrderDirector
{
    private IBuilder builder;
    public OrderDirector(IBuilder builder)
    {
        this.builder = builder;
    }
    public void Construct(int ordertype, string productline, string productName, int quantity, decimal price, string username="")
    {
        builder.SetProductLine(productline)
            .AddProduct(productName, quantity, price);
        switch (ordertype)
        {
            case 1:
                OperationOnlineOrder(builder, username);
                break;
            case 2:
                OperationOffOrder(builder);
                break;
        }
    }
    public IBuilder OperationOnlineOrder(IBuilder builder, string username) 
    {
        return builder.SetUsername(username);
    }
    public IBuilder OperationOffOrder(IBuilder builder)
    {
        return builder;
    }
}

结果输出:

  

二、生成器模式结构

根据上一章节的示例代码,简单画一个 UML 图,如下:

IBuilder:为创建一个 Order 对象的各个信息而指定抽象接口。

OrderBuilder:实现 IBuilder 的接口以构造和装配该订单的各个部件;定义并明确它所创建的表示;提供一个获取订单的接口。

OrderDirector:构造一个使用 IBuilder 接口的对象。

Order:表示被构造的复杂对象。OrderBuilder 创建该订单的内部表示并定义它的装配过程。包含定义组成部件的类,包括将这些部件装配成最终产品的接口。

三、在 .Net 框架中的实际应用

例如在 WebAPI 项目中的 Program.cs 文件中的主方法 Main(),CreateHostBuilder(args).Build().Run()在 WebHost 构建时采用了生成器模式。

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

 其生成器接口定义如下,其中 Configure 系列的配置方法均返回构建器接口类,以便在构建时,可以方便的对配置进行连续配置,这也是链式调用的经典场景之一。例如,构建时可以使用CreateHostBuilder(args).ConfigureAppConfiguration(a=>a.builder()).ConfigureServices((builder,s)=>s.register()).Build();,这样感觉像一个流水线机器一样,逐步构建完毕各个部分,最后生成出预制件。

// Microsoft.Extensions.Hosting.Abstractions, Version=5.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
// Microsoft.Extensions.Hosting.IHostBuilder
using System;
using System.Collections.Generic;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

public interface IHostBuilder
{
	IDictionary<object, object> Properties { get; }

	IHostBuilder ConfigureHostConfiguration(Action<IConfigurationBuilder> configureDelegate);

	IHostBuilder ConfigureAppConfiguration(Action<HostBuilderContext, IConfigurationBuilder> configureDelegate);

	IHostBuilder ConfigureServices(Action<HostBuilderContext, IServiceCollection> configureDelegate);

	IHostBuilder UseServiceProviderFactory<TContainerBuilder>(IServiceProviderFactory<TContainerBuilder> factory);

	IHostBuilder UseServiceProviderFactory<TContainerBuilder>(Func<HostBuilderContext, IServiceProviderFactory<TContainerBuilder>> factory);

	IHostBuilder ConfigureContainer<TContainerBuilder>(Action<HostBuilderContext, TContainerBuilder> configureDelegate);

	IHost Build();
}

四、相关模式

AbstractFactory 与 Builder 相似,因为它也可以创建复杂对象。主要区别是 Builder 模式侧重于一步步构造一个复杂的对象,而 AbstractFactory 侧重于多个系列的产品对象(简单或复杂的)。Builder 在最后一步返回产品,而 AbstractFactory 产品时立即返回的。

另外,Composite 组合模式是用 Builder 生成的。

参考: https://www.cnblogs.com/zhuYears/archive /2012/05/25/2518008.html  https://www.cnblogs.com/gaochundong/p/design_pattern_builder.html  https://juejin.cn/post/6991323757335805960             

与Builder 生成器模式简介与 C# 示例【创建型2】【设计模式来了_2】相似的内容:

Builder 生成器模式简介与 C# 示例【创建型2】【设计模式来了_2】

在构造一个复杂的对象(参数多且有可空类型)时,通过一个统一的构造链路,可选择的配置所需属性值,灵活实现可复用的构造过程。

使用Electron-builder将web项目封装客户端安装包 发布

背景:之前用electron-packager将web项目打包成客户端时,exe文件只能在当前文件夹下运行,如果发送给别人使用 极不方便。所以我们可以用electron-builder将web项目封装成安装包给别人使用。 1、配置npm代理 npm set electron_mirror=https

java与es8实战之一:以builder pattern开篇

欣宸原创《java与es8实战》系列的开篇,重温经典,夯实基础,再出发

Electron Mac 打包报 Error: Exit code: ENOENT. spawn /usr/bin/python ENOENT 解决方法

Electron 项目使用vue-cli-electron-builder创建,原来我的 Mac 上编译都很正常 自从 Mac 升级到 mac OS ventura version 13.0.1 后打包报错,electron-builder 编译 dmg 安装包编译不出来 报如下错误 • build

java与es8实战之六:用JSON创建请求对象(比builder pattern更加直观简洁)

向ES发送请求时,如何创建请求对象呢?官方推荐的builder patter,在面对复杂的请求对象结构时还好用吗?有没有更加直观简洁的方法,尽在本文一网打尽

ElasticSearch 实现分词全文检索 - Java SpringBoot ES 索引操作

//1. 准备索引的 settings Settings.Builder settings = Settings.builder() //2. 准备索引的结构 Mappings XContentBuilder mappings = JsonXContent.contentBuilder() //3. 将 Settings 和 Mappings 封装到一个Request 对象中

Salesforce LWC学习(四十) dynamic interaction 浅入浅出

本篇参考: Configure a Component for Dynamic Interactions in the Lightning App Builder - Salesforce Lightning Component Library Salesforce Help | Article G

告别Word,用Python打造你的专业简历!

今天给大家介绍下一个在纯 python 中构建简历的实用工具,工具的连接地址https://github.com/koek67/resume-builder/blob/main/readme.md 用法介绍 要求 Python 3.7 或更高版本(仅此而已!) 安装 整个库是一个单独的 python

微服务实践k8s&dapr开发部署实验(3)订阅发布

自托管模式运行dapr 新建订阅webapi项目,取名为backend 项目增加docker支持,取消https支持 修改Program.cs var builder = WebApplication.CreateBuilder(args); builder.Services.AddControll

Nuxt3 的生命周期和钩子函数(五)

摘要:本文详细介绍了Nuxt3中的六个核心生命周期钩子及其用法,包括build:done、build:manifest、builder:generateApp、builder:watch、pages:extend和server:devHandler:handler。内容涵盖各钩子的调用时机、参数、环...