C# 设计模式:建造者
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/696027/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Design Pattern: Builder
提问by Zachary Scott
I have looked for a goodexample of a Builder pattern(in C#), but cannot find one either because I don't understand the Builder pattern or I am trying to do something that was never intended. For example, if I have an abstract automobile and abstract builder methods to create car parts, I should be able to send all 30 of my choices to the Director, have it build the pieces I need, then build my automobile. Regardless of which car, truck, semi, etc. produced, I should be able to "drive" it in exactly the same way.
我一直在寻找Builder 模式的一个很好的例子(在 C# 中),但找不到一个,因为我不理解 Builder 模式,或者我正在尝试做一些从未打算过的事情。例如,如果我有一个抽象的汽车和抽象的构建器方法来创建汽车部件,我应该能够将我的所有 30 个选择发送给 Director,让他构建我需要的部件,然后构建我的汽车。无论生产哪种汽车、卡车、半挂车等,我都应该能够以完全相同的方式“驾驶”它。
First problem is most examples hard code property values in to the concrete parts, which I really think should come from a database. I thought the idea was to send my choices to the Director (from a data source) and have the builder create a customized product based on my data.
第一个问题是大多数示例将属性值硬编码到具体部分中,我认为这应该来自数据库。我认为这个想法是将我的选择发送给总监(来自数据源),并让构建者根据我的数据创建定制产品。
Second problem is I want the builder methods to actually create the parts then assign them to the product, not pass strings but real strongly typed product parts.
第二个问题是我希望构建器方法实际创建部件,然后将它们分配给产品,而不是传递字符串,而是真正的强类型产品部件。
For example, I want to create a form on the fly by having a Builder manufacture form fields for me, including a label, an input section, validation, etc. This way I can read the object from my ORM, check out the object's metadata, pass this to my Builder and add the newly created user control result to my web form.
例如,我想通过为我提供一个 Builder 制造表单字段来即时创建一个表单,包括标签、输入部分、验证等。这样我就可以从我的 ORM 中读取对象,查看对象的元数据,将其传递给我的 Builder 并将新创建的用户控件结果添加到我的 Web 表单中。
However, every Builder example I find only has hard coded data instead of passing choices from the main code to the Builder and kicking out a customized product. Everything seems to be a big static case statement. For example, if I have three parameters with 10 choices each, I don't want to build 30 concrete Builder methods, I want to create only enough to manufacture the properties my product requires, which may be only three.
但是,我发现的每个 Builder 示例都只有硬编码数据,而不是将选择从主代码传递到 Builder 并推出定制产品。一切似乎都是一个很大的静态 case 语句。例如,如果我有三个参数,每个参数有 10 个选项,我不想构建 30 个具体的 Builder 方法,我只想创建足以制造我的产品所需的属性,这可能只有三个。
I am tempted to have the Director exist in the main code only. There should be a way to automatically determine which concrete builder method to call similar to polymorphism and method overloads (although that is a very bad example) instead of using a case statement within the pattern. (Every time I need to add a new product type, I will need to modify the existing Director, which is bad).
我很想让 Director 只存在于主代码中。应该有一种方法可以自动确定调用哪个具体的构建器方法,类似于多态和方法重载(尽管这是一个非常糟糕的例子),而不是在模式中使用 case 语句。(每次需要添加新的产品类型时,都需要修改现有的Director,这很糟糕)。
采纳答案by RS Conley
I am going refer to the C# example in the Wikipedia Article here.
我将在此处参考维基百科文章中的 C# 示例。
First problem is most examples hard code property values in to the concrete parts, which I really think should come from a database. I thought the idea was to send my choices to the Director (from a data source) and have the builder create a customized product based on my data.
第一个问题是大多数示例将属性值硬编码到具体部分中,我认为这应该来自数据库。我认为这个想法是将我的选择发送给总监(来自数据源),并让构建者根据我的数据创建定制产品。
In this case you would have class implementing PizzaBuilder that knows how to retrieve data from a database. You can do it several ways.
在这种情况下,您将拥有实现 PizzaBuilder 的类,该类知道如何从数据库中检索数据。您可以通过多种方式做到这一点。
One would be make a HawaiianPizzaBuilder. When the class initializes it queries the database for a Hawaiian Pizza and retrieves the row. Then when the various Build(x) methods are called it would set the properties to the corresponding field of the retrieved database row.
一个是制作一个夏威夷比萨生成器。当该类初始化时,它会在数据库中查询夏威夷披萨并检索该行。然后,当调用各种 Build(x) 方法时,它会将属性设置为检索到的数据库行的相应字段。
Another would be just makes a PizzaDatabaseBuilder and make sure that when you initialize the class you pass it the ID of the row you need for that type of pizza. For example instead of
另一种方法是创建一个 PizzaDatabaseBuilder 并确保在初始化类时向它传递该类型比萨所需的行的 ID。例如代替
waiter.PizzaBuilder = new HawaiianPizzaBuilder();
You use
你用
waiter.PizzaBuilder = new PizzaDatabaseBuilder("Hawaiian");
Second problem is I want the builder methods to actually create the parts then assign them to the product, not pass strings but real strongly typed product parts.
第二个问题是我希望构建器方法实际创建部件,然后将它们分配给产品,而不是传递字符串,而是真正的强类型产品部件。
Should not be an issue. What you need is an other Factory/Builder type pattern to initialize the fields of the Pizza. For example
应该不是问题。您需要的是其他 Factory/Builder 类型模式来初始化 Pizza 的字段。例如
instead of
代替
public override void BuildDough() { pizza.Dough = "pan baked"; }
you would do something like
你会做类似的事情
public override void BuildDough() { pizza.Dough = new DoughBuilder("pan baked"); }
or
或者
public override void BuildDough() { pizza.Dough = new PanBakedDoughBuilder(); }
DoughBuilder can go to another table in your database to properly fill out a PizzaDough Class.
DoughBuilder 可以转到数据库中的另一个表来正确填写 PizzaDough 类。
回答by Rashack
I would say that you cannot avoid either of these - having few overloads for your parts and having a case/if statement somewhere down the stack. Also having to modify your code when adding new class might be your only option.
我会说您无法避免其中任何一个 - 您的部件很少有重载并且在堆栈的某处有一个 case/if 语句。添加新类时还必须修改代码可能是您唯一的选择。
That being said you can get help with some other patters - namely Factory that could aid you in the building process. Also sensible use of polymorphism (e.g. all parts inherit from the some type be it class or interface) can reduce the amount of ifs/cases and overloads.
话虽如此,您可以获得其他一些模式的帮助 - 即可以在构建过程中帮助您的工厂。此外,明智地使用多态(例如,所有部分都继承自某个类型,无论是类还是接口)可以减少 ifs/cases 和重载的数量。
Hope this helps.
希望这可以帮助。
回答by Tobias
Mostly the call of a BuilderPattern looks like this:
大部分 BuilderPattern 的调用如下所示:
Car car = new CarBuilder().withDoors(4).withColor("red").withABS(true).build();
回答by J?rg W Mittag
I've never thought about it this way, but LINQ (the pattern, not the syntax) is actually a builder, right?
我从来没有这样想过,但 LINQ(模式,而不是语法)实际上是一个构建器,对吧?
It's a fluent interface that builds a query and can create queries in different representations (SQL, in-memory object queries, webservice queries, Bart de Smet even wrote an implementation of Linq-to-Excel).
它是一个流畅的界面,可以构建查询并可以创建不同表示形式的查询(SQL、内存中对象查询、Web 服务查询,Bart de Smet 甚至编写了 Linq-to-Excel 的实现)。