我无法确定哪种方法更适合创建具有大量字段(10+)(所有必需的)getter/setter的构造函数方法的对象.构造函数至少要强制设置所有字段.Java Bean更容易看到正在设置哪些变量而不是庞大的列表.构建器模式似乎并不合适,因为所有字段都是必需的,构建器要求您将所有必需参数放在构建器构造函数中.
感谢:D
cle*_*tus 31
更好的方法(imho)是使用某种构建器:
MyClass a = new MyClassBuilder().blah("blah").foo("foo").doStuff().toMyClass();
Run Code Online (Sandbox Code Playgroud)
其中MyClass仍然是不可变的,但具有比具有10个参数的构造函数更可读的创建.
这也称为流畅的界面.Josh Bloch在Effective Java中提到了这一点.
Bri*_*new 27
我的第一个想法是检查你的封装模型是否正确.拥有10个以上的必填字段听起来相当多,也许在这种情况下拥有更细粒度的组件会更有意义吗?
这些字段/参数中的一些是否相关?它们可以组合成有意义的对象(例如x-coordinate,y-coordinate组合成Point对象等)
Car*_*icz 20
史蒂夫麦康奈尔在其着作"完整的代码"中辩称,任何程序都不应超过最多6个,也许7个参数.这些陈述中的大多数不仅仅是他的观点,而是以研究为后盾,例如与代码结构相关的错误率.
罗伯特·马丁的清洁代码甚至更进一步:他建议使用1或2个参数,而3则已经被认为是"代码味道".就个人而言,我认为清洁代码在某些地方有点极端,但总的来说它提出了一些好的论据.
"一大堆参数"(无论多少参数)都表明"厨房水槽"设计有很多事后的想法和很少的结构.它还使维护更加困难和容易出错; 至少,它使代码难以阅读.
所有这些都有充分的理由考虑减少参数的数量.其他答案提供了一些实用的建议.
Yis*_*hai 16
我建议你在这种情况下考虑构建器模式.您可以保证获得有效的对象,而无需拥有大量参数.
OP是更新以拒绝构建器模式,但它似乎是基于误解.Builder模式存在的事实不会删除所有参数的强制执行.
考虑以下对象:
public class SomeImmutableObject {
private String requiredParam1;
private String requiredParam2;
//etc.
private SomeImmutableObject() { //cannot be instantiated outside the class }
public static class Builder {
private SomeImmutableObject instance;
public Builder() { instance = new SomeImmutableObject();
public Builder setParameter1(String value) {
instance.requiredParam1 = value;
return this;
}
//etc for each parameter.
public SomeImmutableObject build() {
if (instance.requiredParam1 == null || instance.requiredParam2 == null /*etc*/)
throw new IllegalStateException("All required parameters were not supplied.");
return instance;
}
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,通过将字段包设为私有并将构建器放在同一个包中,您可以完成基本相同的操作.
如果由于某种原因你不能这样做,你仍然可以使用10个参数的构造函数,然后让Builder成为调用该构造函数的唯一东西,这样它就是一个更容易使用的API.
因此,对于所有声明的要求,Builder模式工作得很好.需要所有10个参数这一事实并不会取消构建器模式的资格.如果模式不满足其他需要,请详细说明.
编辑:OP添加了一个评论(很久以前,但我刚刚在这个问题上得到了一个upvote,所以我现在才看到它),并提出了一个有趣的问题:如何在以后的某个时间点验证原语?
有几种方法可以解决这个问题,包括一个保护布尔值,但我首选的方法是使用Double对象:
private Double doubleForPrimitive;
public Builder setDouble(double d) {
doubleForPrimitive = d;
}
public SomeImmutableObject build() {
if(doubleForPrimitive != null) {
instance.doubleParam = doubleForPrimitive;
} else {
throw new IllegalArgumentExcepion("The parameter double was not provided");
}
//etc.
}
Run Code Online (Sandbox Code Playgroud)
应该注意的是,如果你需要真正的线程安全不变性,将不可变对象的所有字段都作为final,这需要更多样板(将变量存储在构建器中并将它们传递给不可变对象的私有构造函数),但是从客户端代码的角度来看,这种方法仍然很简洁.
恕我直言,您应该根据构造函数中的业务逻辑传递对象有效所需的所有内容。
如果参数列表很长,您可以创建一个包含参数的对象并传递它。