你什么时候会使用建造者模式?[英] When would you use the Builder Pattern?

本文是小编为大家收集整理的关于你什么时候会使用建造者模式?的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

使用构建器模式的一些 common ,现实世界示例?它买了什么?为什么不使用工厂模式?

推荐答案

建筑商和工厂恕我直言之间的关键区别在于,当您需要做很多事情来构建对象时,建筑商很有用.例如,想象一个DOM.您必须创建大量节点和属性才能获取最终对象.当工厂可以在一个方法调用中轻松创建整个对象时,使用工厂.

使用构建器的一个示例是构建XML文档,我在构建HTML片段时使用了此模型(未显示参数):

BuildOrderHeaderRow()
BuildLineItemSubHeaderRow()
BuildOrderRow()
BuildLineItemSubRow()

然后,这个建筑商会为我吐出HTML.这比浏览大型程序方法要容易得多.

查看 wikipedia上的建筑商模式.

其他推荐答案

以下是Java中使用模式和示例代码的一些原因,但这是 Design Design模式中四个团伙涵盖的构建器模式的实现.您在Java中使用它的原因也适用于其他编程语言.

正如Joshua Bloch在有效Java,2nd版本:

当设计构造函数或静态工厂的类别时,构建器模式是一个不错的选择.

我们在某个时候都遇到了一个带有构造函数列表的类,其中每个添加添加了一个新的选项参数:

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

这称为望远镜构造函数.这种模式的问题是,一旦构造函数长4或5个参数,就会变得很难记住所需的参数的顺序以及在给定情况下可能想要的特定构造函数.

一个替代性您必须使用望远镜构造函数模式是 Javabean模式在其中您调用具有强制性参数的构造函数,然后在以下情况下调用任何可选设置器:

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

这里的问题是,由于该对象是通过几个调用来创建的,因此在其构造中可能处于不一致的状态.这也需要大量额外的努力来确保线程安全.

更好的选择是使用构建器图案.

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;
  }
}

请注意,披萨是不可变的,并且参数值全部位于一个位置.因为构建器的设置器方法返回构建器对象,它们能够被链接.

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

这将导致代码易于编写并且非常易于阅读和理解.在此示例中,可以修改构建方法以在具有如果提供了无效的参数值,则从构建器复制到披萨对象,投掷illegalstateException.此模式是灵活的,并且将来很容易添加更多参数.只有在您要为构造函数的4或5个参数具有4或5个参数时,才真正有用.也就是说,如果您怀疑将来可能会添加更多参数,那么首先可能值得.

我已经从Joshua Bloch的《有效的Java》(有效的Java,第二版)上借了大量借来的话题.要了解有关这种模式和其他有效Java实践的更多信息我强烈建议您.

其他推荐答案

考虑一家餐厅.创建"今天的餐点"是一种工厂图案,因为您告诉厨房"让我今天的餐",而厨房(工厂)决定基于隐藏条件的物体.

.

如果您订购自定义比萨饼,则会出现构建器.在这种情况下,服务员告诉厨师(建筑商)"我需要披萨;加奶酪,洋葱和培根!"因此,构建器公开了生成的对象应具有的属性,但隐藏了如何设置它们.

本文地址:https://www.itbaoku.cn/post/627436.html

问题描述

What are some common, real world examples of using the Builder Pattern? What does it buy you? Why not just use a Factory Pattern?

推荐答案

The key difference between a builder and factory IMHO, is that a builder is useful when you need to do lots of things to build an object. For example imagine a DOM. You have to create plenty of nodes and attributes to get your final object. A factory is used when the factory can easily create the entire object within one method call.

One example of using a builder is a building an XML document, I've used this model when building HTML fragments for example I might have a Builder for building a specific type of table and it might have the following methods (parameters are not shown):

BuildOrderHeaderRow()
BuildLineItemSubHeaderRow()
BuildOrderRow()
BuildLineItemSubRow()

This builder would then spit out the HTML for me. This is much easier to read than walking through a large procedural method.

Check out Builder Pattern on Wikipedia.

其他推荐答案

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. The reasons you would use it in Java are also applicable to other programming languages as well.

As Joshua Bloch states in Effective Java, 2nd Edition:

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. 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.

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:

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.

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. Because the Builder's setter methods return the Builder object they are able to be chained.

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. 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. 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. To learn more about this pattern and other effective Java practices I highly recommend it.

其他推荐答案

Consider a restaurant. The creation of "today's meal" is a factory pattern, because you tell the kitchen "get me today's meal" and the kitchen (factory) decides what object to generate, based on hidden criteria.

The builder appears if you order a custom pizza. In this case, the waiter tells the chef (builder) "I need a pizza; add cheese, onions and bacon to it!" Thus, the builder exposes the attributes the generated object should have, but hides how to set them.