it-swarm.com.de

Konstruktoren mit vielen Parametern verwalten in Java

In einigen unserer Projekte gibt es eine Klassenhierarchie, die im Verlauf der Kette weitere Parameter hinzufügt. Unten können einige Klassen bis zu 30 Parameter haben, von denen 28 nur an den Superkonstruktor übergeben werden.

Ich werde zugeben, dass die Verwendung von automatisiertem DI über Guice eine gute Sache wäre, aber aus technischen Gründen sind diese spezifischen Projekte auf Java beschränkt.

Die Konvention, die Argumente alphabetisch nach Typ zu ordnen, funktioniert nicht, da ein Typ plötzlich nicht mehr in Ordnung sein kann, wenn er überarbeitet wird (der Kreis, den Sie für Argument 2 übergeben haben, ist jetzt eine Form).

Diese Frage könnte zu spezifisch und mit der Kritik "Wenn das Ihr Problem ist, machen Sie es auf Designebene falsch" behaftet sein, aber ich suche nur nach irgendwelchen Gesichtspunkten.

97
Steve Armstrong

Das Builder-Entwurfsmuster kann hilfreich sein. Betrachten Sie das folgende Beispiel

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

Dadurch können wir Code wie schreiben

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

Wenn wir ein erforderliches Feld weglassen (vermutlich ist der Name erforderlich), kann der Student-Konstruktor eine Ausnahme auslösen. Außerdem können wir standardmäßige/optionale Argumente verwenden, ohne die Reihenfolge der Argumente verfolgen zu müssen, da jede Reihenfolge dieser Aufrufe gleich gut funktioniert.

249
Eli Courtwright

Können Sie verwandte Parameter in einem Objekt einkapseln?

b. wenn die Parameter gleich sind


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;

dann könntest du stattdessen haben:


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

Was Sie wahrscheinlich tun möchten, ist eine Builder-Klasse. Dann würden Sie so etwas tun:

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

Siehe Seite 8 und folgende von diese Präsentation von Josh Bloch (PDF) oder diese Rezension von Effective Java

14
Michael Myers

Die Verwendung des Builder-Musters könnte one eine Lösung sein.

Wenn Sie aber erst einmal auf 20 bis 30 Parameter gekommen sind, würde ich vermuten, dass zwischen den Parametern eine hohe Beziehung besteht. Daher ist es (wie vorgeschlagen) wahrscheinlich am sinnvollsten, sie in logisch vernünftige Datenobjekte zu packen. Auf diese Weise kann das Datenobjekt bereits die Gültigkeit von Einschränkungen zwischen den Parametern überprüfen.

Bei all meinen Projekten in der Vergangenheit konnte ich den Code bereinigen, indem ich ein besseres Datenmodell erstellte, sobald ich zu viele Parameter hatte (und das waren 8 statt 28!).

7
Thomas Morgner

Die beste Lösung besteht darin, nicht zu viele Parameter im Konstruktor zu haben. Nur die im Konstruktor wirklich benötigten Parameter sind Parameter, die zur korrekten Initialisierung des Objekts erforderlich sind. Sie können Konstruktoren mit mehreren Parametern haben, aber auch einen Konstruktor mit nur den minimalen Parametern. Die zusätzlichen Konstruktoren rufen diesen einfachen Konstruktor auf und setzen danach die anderen Parameter. Auf diese Weise können Sie das Kettenproblem mit immer mehr Parametern umgehen, haben aber auch einige Convenience-Konstruktoren.

4
Mnementh

Da Sie sich auf Java 1.4 beschränken, wenn Sie DI möchten, dann wäre Spring eine sehr anständige Option. DI ist nur an Stellen hilfreich, an denen die Konstruktorparameter services oder sind etwas, das während der Laufzeit nicht variiert.

Wenn Sie über all diese verschiedenen Konstruktoren verfügen, da Sie variable Optionen zum Erstellen eines Objekts benötigen, sollten Sie ernsthaft die Verwendung des Builder-Musters in Betracht ziehen.

4

Ich kann wirklich empfehlen, Immutables oder POJOBuilder zu verwenden, wenn ich das Builder-Muster verwende.

2
Tomas Bjerre

Das Umgestalten, um die Anzahl der Parameter und die Tiefe Ihrer Vererbungshierarchie zu verringern, ist so ziemlich alles, was ich mir vorstellen kann, da nichts wirklich dazu beitragen kann, die 20-Parameter-Ebene gerade zu halten. Sie müssen nur jeden einzelnen Anruf tätigen, während Sie die Dokumentation lesen.

Eine Möglichkeit besteht darin, einige logisch gruppierte Parameter in einem eigenen übergeordneten Objekt zu gruppieren. Dies hat jedoch eigene Probleme.

1
Aaron Maenpaa