Managing constructors with many parameters in Java
在我们的一些项目中,有一个类层次结构,当它沿着链向下时添加更多的参数。在底部,一些类可以有多达30个参数,其中28个参数刚刚被传递到超级构造函数中。
我承认使用Guice这样的自动化DI会很好,但是由于一些技术上的原因,这些特定的项目被限制在Java上。
按类型按字母顺序组织参数的约定不起作用,因为如果类型被重构(您为参数2传递的圆现在是一个形状),它可能会突然出现无序。
这个问题可能是具体的,充满了"如果这是你的问题,你在设计层面上做的不对"的批评,但我只是在寻找任何观点。
生成器设计模式可能会有所帮助。考虑下面的例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | public class StudentBuilder { private String _name; private int _age = 14; // this has a default private String _motto =""; // most students don't have one public StudentBuilder() { } public Student buildStudent() { return new Student(_name, _age, _motto); } public StudentBuilder name(String _name) { this._name = _name; return this; } public StudentBuilder age(int _age) { this._age = _age; return this; } public StudentBuilder motto(String _motto) { this._motto = _motto; return this; } } |
号
这样我们就可以像
1 2 3 4 5 6 | Student s1 = new StudentBuilder().name("Eli").buildStudent(); Student s2 = new StudentBuilder() .name("Spicoli") .age(16) .motto("Aloha, Mr Hand") .buildStudent(); |
如果我们去掉了一个必需的字段(假定名称是必需的),那么我们可以让学生构造函数抛出一个异常。它允许我们使用默认/可选参数,而不需要跟踪任何类型的参数顺序,因为这些调用的任何顺序都将同样有效。
你能在一个对象中封装相关参数吗?
例如,如果参数如下
1 2 3 4 5 6 |
。
然后你可以有:
1 2 3 4 5 6 7 | <wyn> MyClass(Address homeAddress, int foo, double bar) { super(homeAddress); this.foo = foo; this.bar = bar; } </wyn> |
您可能想做的是创建一个生成器类。然后你会这样做:
1 2 3 4 5 | MyObject obj = new MyObjectBuilder().setXxx(myXxx) .setYyy(myYyy) .setZzz(myZzz) // ... etc. .build(); |
请参阅第8页和下面的Josh Bloch演示文稿(PDF),或对有效Java的回顾
好吧,使用构建器模式可能是一种解决方案。
但一旦你达到20到30个参数,我想参数之间有很高的关系。因此(如建议的那样)将它们包装成逻辑上健全的数据对象可能是最有意义的。这样,数据对象就可以检查参数之间约束的有效性。
对于我过去的所有项目,一旦我达到了有太多参数的地步(那是8而不是28!)我可以通过创建更好的数据模型来清理代码。
当您被限制为Java 1.4时,如果您想要DI,那么Spring将是一个非常不错的选择。DI仅在构造函数参数为服务或运行时不变化的地方有用。
如果您有所有这些不同的构造器,因为您需要关于如何构造对象的变量选项,那么您应该认真考虑使用构建器模式。
最好的解决方案是在构造函数中没有太多参数。构造函数中真正需要的参数是需要正确初始化对象的参数。可以有多个参数的构造函数,也可以有一个只有最小参数的构造函数。附加的构造函数调用这个简单的构造函数,并在该setter之后设置其他参数。这样可以避免使用越来越多的参数时出现链问题,但也有一些方便的构造函数。
我真的可以推荐在使用构建器模式时使用不可变项或pojobuilder。
重构以减少参数的数量和继承层次结构的深度几乎是我能想到的,因为没有什么能真正帮助保持20多个参数的正态性。在查看文档时,您只需要每次打电话。
您可以做的一件事是,将一些逻辑分组的参数分组到它们自己的更高级别对象中,但这有它自己的问题。