Java 没有内部类的生成器模式
假设我有这个生成器模式。我到处搜索,但找不到如果外部类有public constructor,为什么我需要使用内部类Java 没有内部类的生成器模式,java,design-patterns,builder-pattern,Java,Design Patterns,Builder Pattern,假设我有这个生成器模式。我到处搜索,但找不到如果外部类有public constructor,为什么我需要使用内部类 public class User { private final String firstName; private final String surname; private final int age; public User(UserBuilder userBuilder) { this.firstName = userBuilder.firstName;
public class User {
private final String firstName;
private final String surname;
private final int age;
public User(UserBuilder userBuilder) {
this.firstName = userBuilder.firstName;
this.surname = userBuilder.surname;
this.age = userBuilder.age;
}
public static class UserBuilder {
private final String firstName;
private final String surname;
private int age;
public UserBuilder(String firstName, String surname) {
this.firstName = firstName;
this.surname = surname;
}
public UserBuilder age(int age) {
this.age = age;
return this;
}
public User build() {
User user = new User(this);
return user;
}
}
}
在这里,我可以在不使用内部类的情况下重写此代码:
public class User {
private String firstName;
private String surname;
private int age;
public User(String firstName, String surname) {
this.firstName = firstName;
this.surname= surname;
}
public User age(int age) {
this.age = age;
return this;
}
}
}
当我读到构建器模式时,他们说这种模式可以防止大的constructor块。他们使用内置的设置器(流畅的模式)。我不明白为什么我们需要创建内部类,如果我的构造函数是公共的,我可以不使用内部类做同样的事情。
这里是更复杂变量的另一个示例:
class NutritionFacts {
private final int servingSize;
private final int servings;
private int calories;
private int fat;
private int sodium;
private int carbohydrate;
public NutritionFacts(int servingSize, int servings) {
this.servingSize = servingSize;
this.servings = servings;
}
public NutritionFacts calories(int val)
{ calories = val; return this; }
public NutritionFacts fat(int val)
{ fat = val; return this; }
public NutritionFacts sodium(int val)
{ sodium = val; return this; }
public NutritionFacts carbohydrate(int val)
{ carbohydrate = val; return this; }
@Override
public String toString() {
return "NutritionFacts{" +
"servingSize=" + servingSize +
", servings=" + servings +
", calories=" + calories +
", fat=" + fat +
", sodium=" + sodium +
", carbohydrate=" + carbohydrate +
'}';
}
}
构建器模式不是为了提供流畅的样式创建(尽管这是一个很好的好处),而是在存在多个可选参数时提供健全的对象实例化 没有任何意义
公共用户someOptionalParam(字符串someOptionalParam){
this.someOptionalParam=someOptionalParam;
归还这个;
}
因为您得到的User
实例没有完全构造,所以它缺少非可选的名字、姓氏和年龄
builder模式在GangofFour(设计模式:可重用面向对象软件的元素)一书中得到了推广。在Java语言的上下文中,将构建器实现为一个内部类还有其他几个好处
高效Java提供了一个构建器模式示例:
公共级营养学事实{
私人最终整数服务大小;
私人最终服务;
个人最终热量;
私人最终int fat;
私家车;
私人最终投资;
公共静态类生成器{
//所需参数
私人最终整数服务大小;
私人最终服务;
//可选参数-初始化为默认值
私人int卡路里=0;
私有int-fat=0;
钠=0;
私人int=0;
公共建筑商(内部服务规模、内部服务){
this.servingSize=servingSize;
这个。份数=份数;
}
公共建筑商卡路里(int val)
{carries=val;返回此;}
公共建筑商fat(int val)
{fat=val;返回此;}
公共建筑商钠(int val)
{Na钠=val;返回此;}
公共建筑商(int val)
{carbone=val;返回此;}
公共营养学事实构建(){
返回新的营养学事实(本);
}
}
私人营养品(建筑商){
servingSize=builder.servingSize;
份数=建筑商份数;
卡路里=卡路里;
fat=builder.fat;
钠=钠;
碳水化合物=碳水化合物;
}
}
Java缺少一些使模式有用的语言特性。Kotlin具有命名和可选参数,允许将上述示例编写为:
课堂营养事实(
val servingSize:Int,
val servings:Int,
val卡路里:Int=0;
val fat Int=0,
val钠Int=0,
val-Int=0
)
val aFact=营养因子(份数=10份,份数=2份,脂肪=7份)
编辑:感谢您以自己的方式完成了这项练习并重新实施了营养事实
您的实现的问题是它是可变的,而它是可变的唯一原因是因为您实现“构建”部分的方式。在这个特殊的类中,没有任何东西需要可变性
NutritionFacts aFact=新营养因子(1,2)、卡路里(7)、钠(3);
// ....
脂肪酸钠(1)、碳水化合物(9);
也许看起来我在移动门柱,以了解构建器模式通常应该实现的目标,但我暗指了一下
对于这一点,我说过“在Java语言的上下文中,作为内部类的构建器还有其他一些好处。”将构建器放在内部类中的要点是,可以将构造函数设置为私有的,因此创建类实例的唯一方法是使用构建器(而不是直接使用公共构造函数). 如果将构造函数公开,那么就没有很好的理由解释为什么生成器必须是一个内部类。@Jesper我有一个项目,它允许以多种方式配置主对象。配置参数不是针对每种情况引入许多私有构造函数,而是封装在公共构建器创建的参数对象中,公共构建器也使用该参数对象来创建实际对象本身。实际的主类仅公开一个使用此参数对象的构造函数,而不是公开每个配置场景的构造函数。通过适当的模块化,您还可以只向公众公开构建器,并在内部环境中完成所有艰难的初始化工作package@RomanVottner诚然,有多种方法可以实现构建器,并且没有一种方法是所有情况下的“最佳”或“正确”方法。我的回答是要特别说明,将构建器类实现为内部类的主要原因是为了使外部类的构造函数成为私有的-但这不是实现构建器模式的唯一方法。如果我不理解,请原谅,但在我的情况下,我仍然看不到任何区别。这两种代码的工作方式相同。我明白你的意思,但我也可以在外部构造函数中编写非可选参数。仍然不知道为什么我需要一个内部类。事实上,最好编辑谢谢。您的示例非常简单,根本不需要构建器,只需要一个带三个参数的构造函数。尝试一个更复杂的场景,例如上面的NutritionFacts
。请注意,NutritionFacts
的两个示例都创建了有效的实例-所需的实例变量是gua