2008-10-21 18 views
82

In einigen unserer Projekte gibt es eine Klassenhierarchie, die mehr Parameter hinzufügt, wie es in der Kette abläuft. Unten können einige der Klassen bis zu 30 Parameter haben, von denen 28 nur in den Superkonstruktor übergeben werden.Managing Konstruktoren mit vielen Parametern in Java

Ich werde erkennen, dass die Verwendung von automatisierten DI durch etwas wie Guice wäre nett, aber aus bestimmten technischen Gründen sind diese spezifischen Projekte auf Java beschränkt.

Eine Konvention, die Argumente alphabetisch nach Typ zu ordnen, funktioniert nicht, weil wenn ein Typ refaktorisiert wird (der Kreis, den Sie für Argument 2 übergeben, jetzt eine Form ist), kann er plötzlich nicht mehr funktionieren.

Diese Frage könnte zu spezifisch und mit "Wenn das ist Ihr Problem, Sie tun es falsch auf einer Design-Ebene" Kritikpunkte sein, aber ich bin nur auf der Suche nach irgendwelchen Standpunkten.

Antwort

219

Die Builder Design Muster helfen könnten. 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; 
    } 
} 

Auf diese Weise können wir Code wie

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

schreiben Wenn wir ein Pflichtfeld wegzulassen (vermutlich ist erforderlich Name), dann können wir die Schüler Konstruktor eine Ausnahme werfen. Und es lässt uns Standard/optionale Argumente haben, ohne jede Art von Argument Reihenfolge verfolgen zu müssen, da jede Reihenfolge dieser Aufrufe gleich gut funktionieren wird.

+8

Natürlich muss man bei statischen Importen diese "Erbauer" überhaupt nicht "sehen". Sie können beispielsweise den Namen einer statischen Methode (String name) angeben, der einen Builder zurückgibt, und Student (StudentBuilder), der einen Student zurückgibt. Daher Student (Name ("Joe"). Alter (15) .motto ("Ich habe mich selbst nass gemacht")); –

+2

@oxbow_lakes: In Ihrem Beispiel hat die Klasse den Namen der statischen Methode (String name)? – user443854

+0

Technisch gesehen ist es möglich, Student-Klasse zu verwenden, um einen neuen Schüler zu bauen. Ich habe die Methoden in der Student-Klasse hinzugefügt und es hat gut funktioniert. Auf diese Weise brauchte ich keine andere Builder-Klasse. Ich bin mir nicht sicher, ob dies wünschenswert ist. Gibt es einen Grund, eine andere (StudentBuilder) -Klasse zu verwenden, um es zu bauen? – WVrock

1

Refactoring, um die Anzahl der Parameter und Tiefe Ihrer Vererbungshierarchie zu reduzieren, ist so ziemlich alles, was ich mir vorstellen kann, weil nichts wirklich dazu beitragen wird, 20-some-Parameter gerade zu halten. Sie müssen nur auf jeden einzelnen Anruf warten, während Sie sich die Dokumentation ansehen.

Eine Sache, die Sie tun könnten, ist, einige logisch gruppierte Parameter in ihr eigenes höheres Level-Objekt zu gruppieren, aber das hat ihre eigenen Probleme.

3

Die beste Lösung ist, nicht zu viele Parameter im Konstruktor zu haben. Nur Parameter, die wirklich im Konstruktor benötigt werden, sind Parameter, die das Objekt korrekt initialisieren müssen. Sie können Konstruktoren mit mehreren Parametern haben, aber auch einen Konstruktor mit nur den Mindestparametern. Die zusätzlichen Konstruktoren rufen diesen einfachen Konstruktor und danach die Setter auf, um die anderen Parameter zu setzen. Auf diese Weise können Sie das Kettenproblem mit immer mehr Parametern vermeiden, aber auch einige Convenience-Konstruktoren haben.

4

Da Sie auf Java 1.4 beschränkt sind, wenn Sie DI wollen, dann wäre Spring eine sehr anständige Option. DI ist nur dort hilfreich, wo die Konstruktorparameter Services sind oder etwas, das während der Laufzeit nicht variiert.

Wenn Sie all diese verschiedenen Konstruktoren haben, weil Sie variable Optionen zum Konstruieren eines Objekts wünschen, sollten Sie ernsthaft das Builder-Muster in Betracht ziehen.

+0

Bei den Parametern handelt es sich meistens um Dienste, wie Sie bereits erwähnt haben, und deshalb ist DI das, was ich brauche. Ich denke, dass das Builder-Muster, das in einigen anderen Antworten erwähnt wird, genau das ist, was ich mir erhofft habe. –

21

Können Sie verwandte Parameter in einem Objekt kapseln?

zum Beispiel, wenn Parameter wie

 

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önnte man stattdessen haben:

 

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

Nun, die Erbauer mit vielleicht einem Lösung sein.

Aber sobald Sie zu 20 bis 30 Parameter kommen, würde ich vermuten, dass es eine hohe Beziehung zwischen den Parametern gibt. Also (wie vorgeschlagen) ist es wahrscheinlich am sinnvollsten, sie in logisch vernünftige Datenobjekte zu verpacken. Auf diese Weise kann das Datenobjekt bereits die Gültigkeit von Einschränkungen zwischen den Parametern prüfen.

Für alle meine Projekte in der Vergangenheit, sobald ich an den Punkt kam, um zu viele Parameter zu haben (und das war 8 nicht 28!) Ich war in der Lage, den Code zu bereinigen, indem Sie ein besseres Datamodell erstellen.

2

Ich kann wirklich empfehlen, Immutables oder POJOBuilder zu verwenden, wenn Sie das Erbauermuster verwenden.

Verwandte Themen