您好我对构建模式有几个问题吗?
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;
}
}
答案 0 :(得分:6)
首先,阅读builder pattern。
为什么主类中的实例变量是私有的?
因为实例变量应为private
(或protected
),以防止不受信任的代码直接操纵。
为什么内部类声明为静态?
因为构建器需要在构建之前构建,即外层类。
为什么内部类中的实例变量是私有的并重复?
因为(见第一个答案)和(见第二个答案)。
我们在方法中返回Builder对象究竟包含在这个对象中的什么内容?
从setter方法返回构建器对象允许method chaining。
为什么主构造函数是私有的?
所以这个类只能由构建器实例化。
答案 1 :(得分:2)
为什么主类中的实例变量是私有的?
这是任何类实现的良好默认值 - 不是为了揭示实现的内部细节。这不是特定于构建器模式。
为什么内部类声明为静态?
因为您需要在外部类的实例之前创建构建器。
为什么内部类中的实例变量是私有的 重复?
请参阅有关“私人”的第一个答案。至于“重复” - 不确定你是什么意思。
我们在方法中返回Builder对象究竟是什么 包含在这个对象中?
我们返回构建器对象,以便用户能够链接调用,即
builder.widthInches(3.0)
.heightInches(2.0)
...
为什么主构造函数是私有的?
为了阻止从外部访问它 - 并强制用户使用构建器。
您可以read here了解有关构建器模式的更多信息。
答案 2 :(得分:2)
我会尽可能地按照查点的顺序回答你的问题。
为了对对象的属性进行访问控制,主类中的实例变量是私有的。在Java中,对象的大多数字段按惯例是私有的,公共访问器(即Type getField()
和void setField(Type field)
)在必要时公开。
这是因为根据面向对象的原则,除了对象本身之外,应该隐藏所有行为的实现。实际上,这会导致覆盖底层实现的能力(例如,如果您希望封装对象提供存储,或者您希望实现每次都需要数据库提取和更新,而不是存储数据的本地副本。
Builder
类是Plank
类的静态成员,因为它提供了唯一可从外部访问的方法来创建Plank
对象。它紧密地耦合了两个类,因为它们彼此依赖。
重要 :您的代码中有一个非常重要的拼写错误:Builder
类应为public
。
这样做的好处意味着你可以构造一个Builder
并使用它来逐位构造Plank
,而不是将大量属性传递给构造函数。 Builder
是静态的意味着您可以执行此操作以接收带有默认参数的Plank
:
Plank p = (new Plank.Builder()).build();
这些实例变量充当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();
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使用其中之一。
好吧,因为使用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)
在Java中,始终将实例变量设为私有是最佳做法。这是一种封装形式。类负责其自己的字段,并且类外的任何代码都应该通过公共方法(例如Setters和Getters)间接访问这些字段。
有两种类型的嵌套类:静态嵌套类和内部类。在这种情况下,您使用静态嵌套类,因为您以静态方式访问它(即您还没有包含类的实例)。
它们是私有的,原因与主类的实例变量相同。
关键字this
引用当前对象实例,在本例中为Builder
对象。返回当前实例允许调用者链接调用,如
Builder builder = new Builder().widthInches(2.0).heightInches(3.0).thicknessInches(1.5);
强制调用代码使用Builder
是私有的。即使它是私有的,嵌套类(例如Builder#build
)也可以调用它。
答案 4 :(得分:1)
为什么主类中的实例变量是私有的?
这遵循适当的封装。在这种情况下,Plank
的宽度,高度和厚度在创建Plank
后永远不会改变。如果这些字段是公开的,则有人可能会无意中更改现有Plank
的大小。
一般来说,许多程序员错误地将事物设为私有并通过getter和setter方法公开数据。这样,程序员可以保持对类中变量的控制,并且可以根据需要清理数据并控制读/写访问。
为什么内部类声明为static?
Builder
实例与Plank
(或任何其他对象)的特定实例无关。不仅如此,还不能绑定到特定实例,因为Builder
正在尝试创建实例。
将其设为非静态会创建一个有趣的案例,您需要Plank
来创建Plank
。
为什么内部类中的实例变量是私有的并重复?
如上一个答案中所述,Builder
与Plank
分开存在,并在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
。