- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
一句话解释:
在构造一个复杂的对象(参数多且有可空类型)时,通过一个统一的构造链路,可选择的配置所需属性值,灵活实现可复用的构造过程.
生成器模式的重心,在于分离 构建算法 和 具体的构造实现 ,从而使得 构建算法可以重用 。 采用不同的构建实现,产生不同的产品 。所以生成器模式都会存在两个部分:整体构建算法、部件的构造和产品的装配.
官方意图:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示.
一个比喻:(班级与各科课代表) 。
每个班级都需要各科课代表,选人条件也会有多个,比如单科成绩名列前茅、课堂表现活跃等,还有些非必要的条件,例如是否开朗等,根据这些条件就可以制定一个标准,对应的就是统一的 IBuilder 接口。不同的科目都可以实现这个接口去生成自己的课代表.
优点:
缺点:
适用场景:
简言之:当一个类的构造函数参数个数超过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 创建该订单的内部表示并定义它的装配过程。包含定义组成部件的类,包括将这些部件装配成最终产品的接口.
例如在 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】的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
前言: 有时候,一个数据库有多个帐号,包括数据库管理员,开发人员,运维支撑人员等,可能有很多帐号都有比较大的权限,例如DDL操作权限(创建,修改,删除存储过程,创建,修改,删除表等),账户多了,管理
所以我用 Create React App 创建并设置了一个大型 React 应用程序。最近我们开始使用 Storybook 来处理和创建组件。它很棒。但是,当我们尝试运行或构建应用程序时,我们不断遇
遵循我正在创建的控件的代码片段。这个控件用在不同的地方,变量也不同。 我正在尝试编写指令来清理代码,但在 {{}} 附近插入值时出现解析错误。 刚接触 Angular ,无法确定我错过了什么。请帮忙。
我正在尝试创建一个 image/jpeg jax-rs 提供程序类,它为我的基于 post rest 的 Web 服务创建一个图像。我无法制定请求来测试以下内容,最简单的测试方法是什么? @POST
我一直在 Windows 10 的模拟器中练习 c。后来我改用dev C++ IDE。当我在 C 中使用 FILE 时。创建的文件的名称为 test.txt ,而我给出了其他名称。请帮助解决它。 下面
当我们创建自定义 View 时,我们将 View 文件的所有者设置为自定义类,并使用 initWithFrame 或 initWithCode 对其进行实例化。 当我们创建 customUITable
我正在尝试为函数 * Producer 创建一个线程,但用于创建线程的行显示错误。我为这句话加了星标,但我无法弄清楚它出了什么问题...... #include #include #include
今天在做项目时,遇到了需要创建JavaScript对象的情况。所以Bing了一篇老外写的关于3种创建JavaScript对象的文章,看后跟着打了一遍代码。感觉方法挺好的,在这里与大家分享一下。 &
我正在阅读将查询字符串传递给 Amazon 的 S3 以进行身份验证的文档,但似乎无法理解 StringToSign 的创建和使用方式。我正在寻找一个具体示例来说明 (1) 如何构造 String
前言:我对 C# 中任务的底层实现不太了解,只了解它们的用法。为我在下面屠宰的任何东西道歉: 对于“我怎样才能开始一项任务但不等待它?”这个问题,我找不到一个好的答案。在 C# 中。更具体地说,即使任
我有一个由一些复杂的表达式生成的 ILookup。假设这是按姓氏查找人。 (在我们简单的世界模型中,姓氏在家庭中是唯一的) ILookup families; 现在我有两个对如何构建感兴趣的查询。 首
我试图创建一个 MSI,其中包含 和 exe。在 WIX 中使用了捆绑选项。这样做时出错。有人可以帮我解决这个问题。下面是代码: 错误 error LGH
在 Yii 中,Create 和 Update 通常使用相同的形式。因此,如果我在创建期间有电子邮件、密码、...other_fields...等字段,但我不想在更新期间专门显示电子邮件和密码字段,但
上周我一直在努力创建一个给定一行和一列的 QModelIndex。 或者,我会满足于在已经存在的 QModelIndex 中更改 row() 的值。 任何帮助,将不胜感激。 编辑: QModelInd
出于某种原因,这不起作用: const char * str_reset_command = "\r\nReset"; const char * str_config_command = "\r\nC
现在,我有以下由 original.df %.% group_by(Category) %.% tally() %.% arrange(desc(n)) 创建的 data.frame。 DF 5),
在今天之前,我使用/etc/vim/vimrc来配置我的vim设置。今天,我想到了创建.vimrc文件。所以,我用 touch .vimrc cat /etc/vim/vimrc > .vimrc 所
我可以创建一个 MKAnnotation,还是只读的?我有坐标,但我发现使用 setCooperative 手动创建 MKAnnotation 并不容易。 想法? 最佳答案 MKAnnotation
在以下代码中,第一个日志语句按预期显示小数,但第二个日志语句记录 NULL。我做错了什么? NSDictionary *entry = [[NSDictionary alloc] initWithOb
我正在使用与此类似的代码动态添加到数组; $arrayF[$f+1][$y][$x+1] = $value+1; 但是我在错误报告中收到了这个: undefined offset :1 问题:尝试创
我是一名优秀的程序员,十分优秀!