在Java中管理具有许多参数的构造函数

时间:2008-10-21 15:04:57

标签: java

在我们的一些项目中,有一个类层次结构,它可以在链中向下添加更多参数。在底部,一些类最多可以有30个参数,其中28个只是被传递给超级构造函数。

我会承认,通过像Guice之类的东西使用自动化DI会很好,但由于某些技术原因,这些特定项目受限于Java。

按类型按字母顺序组织参数的约定不起作用,因为如果一个类型被重构(你为参数2传入的圆现在是一个Shape),它可能会突然出现故障。

这个问题可能具体而且充满了“如果这是你的问题,你在设计层面做错了”批评,但我只是在寻找任何观点。

8 个答案:

答案 0 :(得分:244)

Builder Design Pattern可能有所帮助。请考虑以下示例

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;
    }
}

这让我们可以编写像

这样的代码
Student s1 = new StudentBuilder().name("Eli").buildStudent();
Student s2 = new StudentBuilder()
                 .name("Spicoli")
                 .age(16)
                 .motto("Aloha, Mr Hand")
                 .buildStudent();

如果我们省略了一个必填字段(可能是名称是必需的),那么我们可以让Student构造函数抛出异常。 它允许我们使用默认/可选参数,而不需要跟踪任何类型的参数顺序,因为这些调用的任何顺序都可以正常工作。

答案 1 :(得分:21)

可以在对象中封装相关参数吗?

例如,如果参数类似于


MyClass(String house, String street, String town, String postcode, String country, int foo, double bar) {
  super(String house, String street, String town, String postcode, String country);
  this.foo = foo;
  this.bar = bar;

然后你可以改为:


MyClass(Address homeAddress, int foo, double bar) {
  super(homeAddress);
  this.foo = foo;
  this.bar = bar;
}

答案 2 :(得分:14)

您可能想要做的是拥有一个Builder类。然后你会做这样的事情:

MyObject obj = new MyObjectBuilder().setXxx(myXxx)
                                    .setYyy(myYyy)
                                    .setZzz(myZzz)
                                    // ... etc.
                                    .build();

请参阅第8页及以下this Josh Bloch presentation(PDF)或this review of Effective Java

答案 3 :(得分:7)

好吧,使用构建器模式可能是一个解决方案。

但是一旦你得到20到30个参数,我猜测参数之间存在很高的关系。所以(如建议的那样)将它们包装成逻辑上理智的数据对象可能是最有意义的。这样,数据对象就已经可以检查参数之间约束的有效性。

对于我过去的所有项目,一旦我达到了太多参数(那就是8而不是28!),我就能够通过创建更好的数据模型来清理代码。

答案 4 :(得分:4)

最好的解决方案是在构造函数中没有太多参数。只有构造函数中真正需要的参数才是需要正确初始化对象的参数。您可以使用具有多个参数的构造函数,但也可以使用仅具有最小参数的构造函数。其他构造函数调用这个简单的构造函数,然后在setter之后设置其他参数。这样你就可以避免链式问题越来越多的params,但也有一些方便构造函数。

答案 5 :(得分:4)

由于您受限于Java 1.4,如果您想要DI,那么Spring将是一个非常不错的选择。 DI仅在构造函数参数是服务的地方或在运行时不变的地方有用。

如果您拥有所有这些不同的构造函数,因为您需要有关如何构造对象的变量选项,那么您应该认真考虑使用Builder模式。

答案 6 :(得分:2)

我真的建议在使用构建器模式时使用ImmutablesPOJOBuilder

答案 7 :(得分:1)

重构以减少参数数量和继承层次结构的深度几乎是我能想到的,因为没有什么能真正帮助保持20个参数的直接。在查看文档时,您只需要拨打每一个电话。

你可以做的一件事是将一些逻辑分组的参数分组到他们自己的更高级别的对象中,但这有它自己的问题。