高效 Java 中的构建器模式
我最近开始阅读 Joshua Bloch 所著的《Effective Java》。我发现 Builder 模式 [书中第 2 项] 的想法非常有趣。我尝试在我的项目中实现它,但出现编译错误。以下本质上是我想做的事情:
具有多个属性的类及其构建器类:
public class NutritionalFacts {
private int sodium;
private int fat;
private int carbo;
public class Builder {
private int sodium;
private int fat;
private int carbo;
public Builder(int s) {
this.sodium = s;
}
public Builder fat(int f) {
this.fat = f;
return this;
}
public Builder carbo(int c) {
this.carbo = c;
return this;
}
public NutritionalFacts build() {
return new NutritionalFacts(this);
}
}
private NutritionalFacts(Builder b) {
this.sodium = b.sodium;
this.fat = b.fat;
this.carbo = b.carbo;
}
}
我尝试使用上述类的类:
public class Main {
public static void main(String args[]) {
NutritionalFacts n =
new NutritionalFacts.Builder(10).carbo(23).fat(1).build();
}
}
我收到以下编译器错误:
包含的封闭实例 effectivejava.BuilderPattern.NutritionalFacts.Builder 是必须的 营养成分 n = 新 NutritionalFacts.Builder(10).carbo(23).fat(1).build();
我不明白该消息的含义。请解释一下。上面的代码与 Bloch 在他的书中建议的示例类似。
I have recently started to read Effective Java by Joshua Bloch. I found the idea of the Builder pattern [Item 2 in the book] really interesting. I tried to implement it in my project but there were compilation errors. Following is in essence what I was trying to do:
The class with multiple attributes and its builder class:
public class NutritionalFacts {
private int sodium;
private int fat;
private int carbo;
public class Builder {
private int sodium;
private int fat;
private int carbo;
public Builder(int s) {
this.sodium = s;
}
public Builder fat(int f) {
this.fat = f;
return this;
}
public Builder carbo(int c) {
this.carbo = c;
return this;
}
public NutritionalFacts build() {
return new NutritionalFacts(this);
}
}
private NutritionalFacts(Builder b) {
this.sodium = b.sodium;
this.fat = b.fat;
this.carbo = b.carbo;
}
}
Class where I try to use the above class:
public class Main {
public static void main(String args[]) {
NutritionalFacts n =
new NutritionalFacts.Builder(10).carbo(23).fat(1).build();
}
}
I am getting the following compiler error:
an enclosing instance that contains
effectivejava.BuilderPattern.NutritionalFacts.Builder
is required
NutritionalFacts n = new
NutritionalFacts.Builder(10).carbo(23).fat(1).build();
I do not understand what the message means. Please explain. The above code is similar to the example suggested by Bloch in his book.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(12)
使构建器成为静态类。然后它就会起作用。如果它是非静态的,则它将需要其所属类的实例 - 重点是不要拥有它的实例,甚至禁止在没有构建器的情况下创建实例。
参考:嵌套类
Make the builder a
static
class. Then it will work. If it is non-static, it would require an instance of its owning class - and the point is not to have an instance of it, and even to forbid making instances without the builder.Reference: Nested classes
您应该将 Builder 类设置为静态,并且还应该将字段设置为最终字段,并使用 getter 来获取这些值。不要为这些值提供设置器。这样你的类将是完全不可变的。
现在您可以按如下方式设置属性:
You should make the Builder class as static and also you should make the fields final and have getters to get those values. Don't provide setters to those values. In this way your class will be perfectly immutable.
And now you can set the properties as follows:
要在 Intellij IDEA 中生成内部构建器,请查看此插件:https://github.com/analytically/innerbuilder
To generate an inner builder in Intellij IDEA, check out this plugin: https://github.com/analytically/innerbuilder
您正在尝试以静态方式访问非静态类。将 Builder 更改为 static class Builder ,它应该可以工作。
您提供的示例用法失败,因为不存在 Builder 实例。出于所有实际目的的静态类总是被实例化。如果您不将其设为静态,您需要说:
因为您每次都需要构造一个新的
Builder
。You are trying access a non-static class in a static way. Change
Builder
tostatic class Builder
and it should work.The example usage you give fails because there is no instance of
Builder
present. A static class for all practical purposes is always instantiated. If you don't make it static, you'd need to say:Because you would need to construct a new
Builder
every time.您需要将
Builder
内部类声明为static
。请查阅非静态内部类和静态内部类。
基本上,如果没有附加的外部类实例,非静态内部类实例就不能存在。
You need to declare the
Builder
inner class asstatic
.Consult some documentation for both non-static inner classes and static inner classes.
Basically the non-static inner classes instances cannot exist without attached outer class instance.
一旦你有了想法,在实践中,你可能会发现 lombok 的
@Builder
更方便。@Builder
可让您自动生成使您的类可实例化所需的代码,例如:官方文档:https://www.projectlombok.org/features/Builder
Once you've got an idea, in practice, you may find lombok's
@Builder
much more convenient.@Builder
lets you automatically produce the code required to have your class be instantiable with code such as:Official documentation: https://www.projectlombok.org/features/Builder
这意味着您无法创建封闭类型。这意味着首先您必须创建“父”类的实例,然后从该实例您可以创建嵌套类实例。
嵌套类
This mean that you cant create enclose type. This mean that first you have to cerate a instance of "parent" class and then from this instance you can create nested class instances.
Nested Classes
Builder 类应该是静态的。我现在没有时间实际测试除此之外的代码,但如果它不起作用,请告诉我,我会再看一下。
The Builder class should be static. I don't have time right now to actually test the code beyond that, but if it doesn't work let me know and I'll take another look.
当你有两个不同的类时,我个人更喜欢使用另一种方法。所以你不需要任何静态类。这基本上是为了避免在必须创建新实例时编写
Class.Builder
。因此,您可以像这样使用您的构建器:
I personally prefer to use the other approach, when you have 2 different classes. So you don't need any static class. This is basically to avoid write
Class.Builder
when you has to create a new instance.So, you can use your builder like this:
正如许多人已经指出的那样,您需要使类
静态
。只是一点小小的补充 - 如果你愿意,有一种没有静态方法的不同方法。
考虑一下这一点。通过在类中声明类似
withProperty(value)
类型设置器的内容来实现构建器,并使它们返回对其自身的引用。在这种方法中,您有一个单一且优雅的类,它是线程安全且简洁的。考虑一下:
查看更多 Java Builder 示例。
As many already stated here you need to make the class
static
.Just small addition - if you want, there is a bit different way without static one.
Consider this. Implementing a builder by declaring something like
withProperty(value)
type setters inside the class and make them return a reference to itself. In this approach, you have a single and an elegant class which is a thread safe and concise.Consider this:
Check it out for more Java Builder examples.
您需要将Builder类更改为静态类Builder。然后它就会工作得很好。
You need to change Builder class to static class Builder. Then it will work fine.
其他解决方案将内存分配加倍以实例化对象。下面的解决方案就不存在这个问题。
The other solutions double the memory allocation to instantiate the object. The following solution does not have that problem.