博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
你什么时候使用Builder模式? [关闭]
阅读量:2379 次
发布时间:2019-05-10

本文共 10679 字,大约阅读时间需要 35 分钟。

本文翻译自:

What are some common , real world examples of using the Builder Pattern? 使用Builder Pattern有哪些常见的 现实世界示例 What does it buy you? 它给你带来了什么? Why not just use a Factory Pattern? 为什么不使用工厂模式?


#1楼

参考:


#2楼

Below are some reasons arguing for the use of the pattern and example code in Java, but it is an implementation of the Builder Pattern covered by the Gang of Four in Design Patterns . 下面是一些争论在Java中使用模式和示例代码的原因,但它是由设计模式中的四人组所涵盖的Builder模式的实现。 The reasons you would use it in Java are also applicable to other programming languages as well. 您在Java中使用它的原因也适用于其他编程语言。

As Joshua Bloch states in : 正如Joshua Bloch在 :

The builder pattern is a good choice when designing classes whose constructors or static factories would have more than a handful of parameters. 在设计构造函数或静态工厂具有多个参数的类时,构建器模式是一个不错的选择。

We've all at some point encountered a class with a list of constructors where each addition adds a new option parameter: 我们在某个时刻遇到了一个带有构造函数列表的类,其中每个添加都添加了一个新的选项参数:

Pizza(int size) { ... }        Pizza(int size, boolean cheese) { ... }    Pizza(int size, boolean cheese, boolean pepperoni) { ... }    Pizza(int size, boolean cheese, boolean pepperoni, boolean bacon) { ... }

This is called the Telescoping Constructor Pattern. 这称为Telescoping Constructor Pattern。 The problem with this pattern is that once constructors are 4 or 5 parameters long it becomes difficult to remember the required order of the parameters as well as what particular constructor you might want in a given situation. 这种模式的问题是,一旦构造函数长度为4或5个参数,就很难记住 参数的所需顺序以及在给定情况下您可能需要的特定构造函数。

One alternative you have to the Telescoping Constructor Pattern is the JavaBean Pattern where you call a constructor with the mandatory parameters and then call any optional setters after: Telescoping构造函数模式的另一个选择JavaBean模式 ,您可以使用必需参数调用构造函数,然后在以下情况下调用任何可选的setter:

Pizza pizza = new Pizza(12);pizza.setCheese(true);pizza.setPepperoni(true);pizza.setBacon(true);

The problem here is that because the object is created over several calls it may be in an inconsistent state partway through its construction. 这里的问题是因为对象是在几次调用中创建的,所以它的构造中途可能处于不一致状态。 This also requires a lot of extra effort to ensure thread safety. 这还需要大量额外的努力来确保线程安全。

The better alternative is to use the Builder Pattern. 更好的选择是使用Builder Pattern。

public class Pizza {  private int size;  private boolean cheese;  private boolean pepperoni;  private boolean bacon;  public static class Builder {    //required    private final int size;    //optional    private boolean cheese = false;    private boolean pepperoni = false;    private boolean bacon = false;    public Builder(int size) {      this.size = size;    }    public Builder cheese(boolean value) {      cheese = value;      return this;    }    public Builder pepperoni(boolean value) {      pepperoni = value;      return this;    }    public Builder bacon(boolean value) {      bacon = value;      return this;    }    public Pizza build() {      return new Pizza(this);    }  }  private Pizza(Builder builder) {    size = builder.size;    cheese = builder.cheese;    pepperoni = builder.pepperoni;    bacon = builder.bacon;  }}

Note that Pizza is immutable and that parameter values are all in a single location . 请注意, Pizza是不可变的,并且参数值都在一个位置 Because the Builder's setter methods return the Builder object they are able to be chained . 因为Builder的setter方法返回Builder对象,所以它们可以被链接

Pizza pizza = new Pizza.Builder(12)                       .cheese(true)                       .pepperoni(true)                       .bacon(true)                       .build();

This results in code that is easy to write and very easy to read and understand. 这导致代码易于编写且易于阅读和理解。 In this example, the build method could be modified to check parameters after they have been copied from the builder to the Pizza object and throw an IllegalStateException if an invalid parameter value has been supplied. 在此示例中, 可以修改构建方法,以便在将参数从构建器复制到Pizza对象后检查参数, 如果提供了无效的参数值 ,则抛出IllegalStateException。 This pattern is flexible and it is easy to add more parameters to it in the future. 这种模式非常灵活,将来很容易为它添加更多参数。 It is really only useful if you are going to have more than 4 or 5 parameters for a constructor. 只有当你要为构造函数提供超过4或5个参数时,它才真正有用。 That said, it might be worthwhile in the first place if you suspect you may be adding more parameters in the future. 也就是说, 如果您怀疑将来可能会添加更多参数 ,那么首先可能是值得的。

I have borrowed heavily on this topic from the book Effective Java, 2nd Edition by Joshua Bloch. 我在Joshua Bloch的Effective Java,2nd Edition一书中大量借用了这个主题。 To learn more about this pattern and other effective Java practices I highly recommend it. 要了解有关此模式和其他有效Java实践的更多信息, 我强烈推荐它。


#3楼

Another advantage of the builder is that if you have a Factory, there is still some coupling in you code, because for the Factory to work, it has to know all the objects it can possibly create . 构建器的另一个优点是,如果你有一个Factory,你的代码中仍然会有一些耦合,因为要使Factory工作,它必须知道它可能创建的所有对象 If you add another object that could be created, you will have to modify the factory class to include him. 如果添加另一个可以创建的对象,则必须修改工厂类以包含他。 This happens in the Abstract Factory as well. 这也发生在抽象工厂中。

With the builder, on the other hand, you just have to create a new concrete builder for this new class. 另一方面,使用构建器,您只需为此新类创建新的具体构建器。 The director class will stay the same, because it receives the builder in the constructor. 导向器类将保持不变,因为它在构造函数中接收构建器。

Also, there are many flavors of builder. 此外,还有许多口味的建设者。 Kamikaze Mercenary`s gives another one. Kamikaze Mercenary的另一个。


#4楼

/// /// Builder/// public interface IWebRequestBuilder{    IWebRequestBuilder BuildHost(string host);    IWebRequestBuilder BuildPort(int port);    IWebRequestBuilder BuildPath(string path);    IWebRequestBuilder BuildQuery(string query);    IWebRequestBuilder BuildScheme(string scheme);    IWebRequestBuilder BuildTimeout(int timeout);    WebRequest Build();}/// /// ConcreteBuilder #1/// public class HttpWebRequestBuilder : IWebRequestBuilder{    private string _host;    private string _path = string.Empty;    private string _query = string.Empty;    private string _scheme = "http";    private int _port = 80;    private int _timeout = -1;    public IWebRequestBuilder BuildHost(string host)    {        _host = host;        return this;    }    public IWebRequestBuilder BuildPort(int port)    {        _port = port;        return this;    }    public IWebRequestBuilder BuildPath(string path)    {        _path = path;        return this;    }    public IWebRequestBuilder BuildQuery(string query)    {        _query = query;        return this;    }    public IWebRequestBuilder BuildScheme(string scheme)    {        _scheme = scheme;        return this;    }    public IWebRequestBuilder BuildTimeout(int timeout)    {        _timeout = timeout;        return this;    }    protected virtual void BeforeBuild(HttpWebRequest httpWebRequest) {    }    public WebRequest Build()    {        var uri = _scheme + "://" + _host + ":" + _port + "/" + _path + "?" + _query;        var httpWebRequest = WebRequest.CreateHttp(uri);        httpWebRequest.Timeout = _timeout;        BeforeBuild(httpWebRequest);        return httpWebRequest;    }}/// /// ConcreteBuilder #2/// public class ProxyHttpWebRequestBuilder : HttpWebRequestBuilder{    private string _proxy = null;    public ProxyHttpWebRequestBuilder(string proxy)    {        _proxy = proxy;    }    protected override void BeforeBuild(HttpWebRequest httpWebRequest)    {        httpWebRequest.Proxy = new WebProxy(_proxy);    }}/// /// Director/// public class SearchRequest{    private IWebRequestBuilder _requestBuilder;    public SearchRequest(IWebRequestBuilder requestBuilder)    {        _requestBuilder = requestBuilder;    }    public WebRequest Construct(string searchQuery)    {        return _requestBuilder        .BuildHost("ajax.googleapis.com")        .BuildPort(80)        .BuildPath("ajax/services/search/web")        .BuildQuery("v=1.0&q=" + HttpUtility.UrlEncode(searchQuery))        .BuildScheme("http")        .BuildTimeout(-1)        .Build();    }    public string GetResults(string searchQuery) {        var request = Construct(searchQuery);        var resp = request.GetResponse();        using (StreamReader stream = new StreamReader(resp.GetResponseStream()))        {            return stream.ReadToEnd();        }    }}class Program{    ///     /// Inside both requests the same SearchRequest.Construct(string) method is used.    /// But finally different HttpWebRequest objects are built.    ///     static void Main(string[] args)    {        var request1 = new SearchRequest(new HttpWebRequestBuilder());        var results1 = request1.GetResults("IBM");        Console.WriteLine(results1);        var request2 = new SearchRequest(new ProxyHttpWebRequestBuilder("localhost:80"));        var results2 = request2.GetResults("IBM");        Console.WriteLine(results2);    }}

#5楼

Check out InnerBuilder, an IntelliJ IDEA plugin that adds a 'Builder' action to the Generate menu (Alt+Insert) which generates an inner builder class as described in Effective Java 查看InnerBuilder,这是一个IntelliJ IDEA插件,它将“Builder”动作添加到Generate菜单(Alt + Insert),生成内部构建器类,如Effective Java中所述


#6楼

I always disliked the Builder pattern as something unwieldy, obtrusive and very often abused by less experienced programmers. 我总是不喜欢Builder模式,因为它不经常,突兀,经常被经验不足的程序员滥用。 Its a pattern which only makes sense if you need to assemble the object from some data which requires a post-initialisation step (ie once all the data is collected - do something with it). 它是一种模式,只有在你需要从需要后初始化步骤的一些数据中组装对象时才会有意义(即一旦收集了所有数据 - 用它做一些事情)。 Instead, in 99% of the time builders are simply used to initialise the class members. 相反,在99%的情况下,构建器仅用于初始化类成员。

In such cases it is far better to simply declare withXyz(...) type setters inside the class and make them return a reference to itself. 在这种情况下,简单地在类中声明withXyz(...)类型的setter并使它们返回withXyz(...)自己的引用要好得多。

Consider this: 考虑一下:

public class Complex {    private String first;    private String second;    private String third;    public String getFirst(){       return first;     }    public void setFirst(String first){       this.first=first;     }    ...     public Complex withFirst(String first){       this.first=first;       return this;     }    public Complex withSecond(String second){       this.second=second;       return this;     }    public Complex withThird(String third){       this.third=third;       return this;     }}Complex complex = new Complex()     .withFirst("first value")     .withSecond("second value")     .withThird("third value");

Now we have a neat single class that manages its own initialization and does pretty much the same job as the builder, except that its far more elegant. 现在我们有一个整洁的单一类来管理它自己的初始化,并且与构建器完成相同的工作,除了它更优雅。

转载地址:http://yuexb.baihongyu.com/

你可能感兴趣的文章
大数据时代企业须把握三个变化
查看>>
华为发布敏捷交换机备战大数据
查看>>
大数据挖掘变革 美赛达软硬云引领车联网商业蓝海
查看>>
大数据市场火爆 互联网思维激发运营商潜能
查看>>
赵先德:不提倡每个人都分析大数据
查看>>
大数据潮起 三领域争抢蛋糕
查看>>
百度助力中小企搜赢大数据
查看>>
大数据风云再起 二线龙头接棒大涨
查看>>
大数据核心就是要预测未来趋势
查看>>
风投掘金可穿戴设备:大数据才是背后真金
查看>>
搞互联网金融的,少点大数据忽悠吧!
查看>>
检测食品质量,看大数据分析
查看>>
地产大数据
查看>>
用大数据卖房
查看>>
2014 酒业营销升级在即 大数据营销
查看>>
停车费上涨需要公开“大数据”
查看>>
民营银行试点四大模式各有侧重 大数据独领风骚
查看>>
深交所跨入大数据监管
查看>>
房地产业探索新模式 大数据买房利好九股
查看>>
大数据和互联网思维或能有效缓解交通拥堵
查看>>