构建Builder模式的原因是什么?

时间:2015-09-14 17:10:28

标签: java design-patterns

您好我对构建模式有几个问题吗?

  1. 为什么主类中的实例变量是私有的?
  2. 为什么内部类声明为static ??
  3. 为什么内部类中的实例变量是私有的并重复?
  4. 我们在方法中返回Builder对象究竟包含在这个对象中的什么内容?
  5. 为什么主构造函数是私有的?
  6. public class Plank {
        //1. Why are these instance variables private?
        private double widthInches;
        private double heightInches;
        private double thicknessInches;
    
        //2. Why is this class static?
        public static class Builder {
            //Why are these instance variables private and repeated?
            private double widthInches;
            private double heightInches;
            private double thicknessInches;
    
            public Builder widthInches(double inches) {
    
                widthInches = inches;
                //3. What is returned here what object is this referencing?
                return this;
    
            }
            public Builder heightInches(double inches) {
                heightInches = inches;
                return this;
            }
            public Builder thicknessInches(double inches) {
                thicknessInches = inches;
                return this;
            }
            public Plank build() {
                return new Plank(this);
            }
        }
        //4. Why is this constructor private?
        private Plank(Builder build) {
            widthInches = build.widthInches;
            heightInches = build.heightInches;
            thicknessInches = build.thicknessInches;
        }
    
    }
    

5 个答案:

答案 0 :(得分:6)

首先,阅读builder pattern

  

为什么主类中的实例变量是私有的?

因为实例变量应为private(或protected),以防止不受信任的代码直接操纵。

  

为什么内部类声明为静态?

因为构建器需要在构建之前构建,即外层类。

  

为什么内部类中的实例变量是私有的并重复?

因为(见第一个答案)和(见第二个答案)。

  

我们在方法中返回Builder对象究竟包含在这个对象中的什么内容?

从setter方法返回构建器对象允许method chaining

  

为什么主构造函数是私有的?

所以这个类只能由构建器实例化。

答案 1 :(得分:2)

  

为什么主类中的实例变量是私有的?

这是任何类实现的良好默认值 - 不是为了揭示实现的内部细节。这不是特定于构建器模式。

  

为什么内部类声明为静态?

因为您需要在外部类的实例之前创建构建器。

  

为什么内部类中的实例变量是私有的   重复?

请参阅有关“私人”的第一个答案。至于“重复” - 不确定你是什么意思。

  

我们在方法中返回Builder对象究竟是什么   包含在这个对象中?

我们返回构建器对象,以便用户能够链接调用,即

builder.widthInches(3.0)
       .heightInches(2.0)
       ...
  

为什么主构造函数是私有的?

为了阻止从外部访问它 - 并强制用户使用构建器。

您可以read here了解有关构建器模式的更多信息。

答案 2 :(得分:2)

我会尽可能地按照查点的顺序回答你的问题。

1。为什么主类中的实例变量是私有的?

为了对对象的属性进行访问控制,主类中的实例变量是私有的。在Java中,对象的大多数字段按惯例是私有的,公共访问器(即Type getField()void setField(Type field))在必要时公开。

这是因为根据面向对象的原则,除了对象本身之外,应该隐藏所有行为的实现。实际上,这会导致覆盖底层实现的能力(例如,如果您希望封装对象提供存储,或者您希望实现每次都需要数据库提取和更新,而不是存储数据的本地副本。

2。为什么内部类声明为静态?

Builder类是Plank类的静态成员,因为它提供了唯一可从外部访问的方法来创建Plank对象。它紧密地耦合了两个类,因为它们彼此依赖。

重要 :您的代码中有一个非常重要的拼写错误:Builder类应为public

这样做的好处意味着你可以构造一个Builder并使用它来逐位构造Plank,而不是将大量属性传递给构造函数。 Builder是静态的意味着您可以执行此操作以接收带有默认参数的Plank

Plank p = (new Plank.Builder()).build();

3。为什么内部类中的实例变量是私有的并重复?

这些实例变量充当Plank个对象的模板。通过逐个配置这些内容,您可以在Plank内逐渐构建Builder,然后拉动触发器并弹出新的Plank。类比是设置木刻机的参数,然后使用这些参数构建一个或多个相同的木板,并提供合理的,可用的默认值。

这意味着您可以执行以下操作:

Plank.Builder builder = new Plank.Builder();
builder.widthInches(13);
builder.heightInches(2);
// Don't set the thickness; use the default defined in the Builder's constructor.
Plank p1 = builder.build();
Plank p2 = builder.build();
// Now set the thickness to a new value
builder.thicknessInches(14);
Plank p3 = builder.build();

4。我们在方法中返回构建器对象究竟包含在该对象中的什么内容?

是的,这是我的最爱之一。这使我们可以执行所谓的方法链接,这类似于字符串连接和数学运算在语言中的工作方式,但是使用变量和函数调用而不是运算符和操作数。这让我们可以做这样的技巧:

Plank p = (new Plank.Builder())
           .heightInches(13)
           .thicknessInches(14)
           .widthInches(12)
           .build();

或者这个:

Plank.Builder builder = (new Plank.Builder())
                         .heightInches(13)
                         .thicknessInches(14)
                         .widthInches(12);
Plank p1 = builder.build();
Plank p2 = builder.build();

当与更好的方法名称结合使用时,这可以用于在朗读时听起来像一个口语单词命令,这是一种被称为“流畅的界面”的模式。 C#的LINQ和Enumerables使用其中之一。

5。为什么主构造函数是私有的?

好吧,因为使用Builder会更好!我们希望避免使用这些类的开发人员使用丑陋的语法,因此我们将丑陋的部分隐藏起来并且不可访问,从而使手指远离使这个模式工作的齿轮,就像它一样。

我们不想想要的是客户端代码中的类似内容:

Plank.Builder builder = new Plank.Builder().heightInches(13);
Plank p1 = new Plank(builder);

这比以前更加丑陋:

Plank p1 = (new Plank.Builder()).heightInches(13).build();

的添加

如果你想进一步清理它,可以使Plank.Builder的构造函数为private,并在Plank中提供以下方法:

public static Plank.Builder getBuilder() {
    return new Plank.Builder();
}

然后,客户端代码将是:

Plank p1 = Plank.getBuilder()
                 .heightInches(13)
                 .build();

答案 3 :(得分:1)

  1. 为什么主类中的实例变量是私有的?
  2. 在Java中,始终将实例变量设为私有是最佳做法。这是一种封装形式。类负责其自己的字段,并且类外的任何代码都应该通过公共方法(例如Setters和Getters)间接访问这些字段。

    1. 为什么内部类声明为static ??
    2. 有两种类型的嵌套类:静态嵌套类内部类。在这种情况下,您使用静态嵌套类,因为您以静态方式访问它(即您还没有包含类的实例)。

      1. 为什么内部类中的实例变量是私有的并重复?
      2. 它们是私有的,原因与主类的实例变量相同。

        1. 我们在方法中返回Builder对象究竟包含在这个对象中的什么内容?
        2. 关键字this引用当前对象实例,在本例中为Builder对象。返回当前实例允许调用者链接调用,如

          Builder builder = new Builder().widthInches(2.0).heightInches(3.0).thicknessInches(1.5);
          
          1. 为什么主构造函数是私有的?
          2. 强制调用代码使用Builder是私有的。即使它是私有的,嵌套类(例如Builder#build)也可以调用它。

答案 4 :(得分:1)

  

为什么主类中的实例变量是私有的?

这遵循适当的封装。在这种情况下,Plank的宽度,高度和厚度在创建Plank后永远不会改变。如果这些字段是公开的,则有人可能会无意中更改现有Plank的大小。

一般来说,许多程序员错误地将事物设为私有并通过getter和setter方法公开数据。这样,程序员可以保持对类中变量的控制,并且可以根据需要清理数据并控制读/写访问。

  

为什么内部类声明为static?

Builder实例与Plank(或任何其他对象)的特定实例无关。不仅如此,还不能绑定到特定实例,因为Builder正在尝试创建实例。

将其设为非静态会创建一个有趣的案例,您需要Plank来创建Plank

  

为什么内部类中的实例变量是私有的并重复?

如上一个答案中所述,BuilderPlank分开存在,并在Plank实例之前创建。因此,它需要拥有它自己的字段副本,以便以后可以创建木板。

同样,将它们保密是允许Builder保留对这些变量的完全控制,确保Builder的用户必须与方法交互才能正确创建Plank

  

我们在方法中返回Builder对象究竟包含在这个对象中的什么内容?

返回的Builder代表Builder的当前状态。以下是一些例子:

// Calling plankBuilder1.build() would create a Plank with no width, height, or thickness.
Plank.Builder plankBuilder1 = new Plank.Builder();

// Calling plankBuilder2.build() would create a Plank with a height, but no width or thickness
Plank.Builder plankBuilder1 = new Plank.Builder().heightInches(1.0);
  

为什么主构造函数是私有的?

Builder模式旨在替换构造函数。程序员可能会发现这种情况有很多原因,但最终结果是您希望此类的使用者使用Builder来创建对象的实例。

如果构造函数是公共的,那么消费者可能会尝试使用它而不是Builder。私有化迫使他们使用Builder