Ein weiterer Tag und noch ein Kampf mit Generika.Java fließenden Builder und Vererbung
Ich habe von Control
Objekten mit dem folgenden Vererbungsbaum gesetzt:
BaseControl
|_SimpleControl
|_MultipleControl
|_AutocompleteControl
|_SelectControl
Für jeden nicht-abstraktes Objekt in diesem Baum Ich mag würde Builder zur Verfügung zu stellen, damit diese Objekte einfach erstellt werden. Hier ist, was ich bisher:
BaseControlBuilder:
public abstract class BaseControlBuilder<C extends BaseControl, B extends BaseControlBuilder<C, B>> {
protected C control;
private B builder;
BaseControlBuilder() {
control = createObj();
builder = getThis();
}
public C build() { return control; }
protected abstract C createObj();
protected abstract B getThis();
}
SimpleControlBuilder:
public class SimpleControlBuilder<C extends SimpleControl, B extends SimpleControlBuilder<C, B>>
extends BaseControlBuilder<SimpleControl, SimpleControlBuilder<C, B>> {
public SimpleControlBuilder(final String id, final String caption,
final InputType controlType) {
super();
control.setId(id);
control.setCaption(caption);
control.setType(controlType);
}
public SimpleControlBuilder(final InputType controlType) {
this("", "", controlType);
}
public SimpleControlBuilder(final Enum<?> en, final InputType controlType) {
this(en.name(), en.toString(), controlType);
}
public SimpleControlBuilder<C, B> disabled() {
control.setDisabled(true);
return this;
}
@Override
protected SimpleControl createObj() {
return new SimpleControl();
}
@Override
protected SimpleControlBuilder<C, B> getThis() {
return this;
}
}
MultipleControlBuilder:
abstract class MultipleControlBuilder<C extends MultipleControl, B extends MultipleControlBuilder<C, B>>
extends SimpleControlBuilder<MultipleControl, MultipleControlBuilder<C, B>> {
MultipleControlBuilder(final InputType type) {
super(type);
}
MultipleControlBuilder(final String id, final String caption,
final InputType type) {
super(id, caption, type);
}
MultipleControlBuilder(final Enum<?> en, final InputType type) {
super(en, type);
}
public MultipleControlBuilder<C, B> multiple() {
((MultipleControl) control).setMultiple(true);
return this;
}
}
AutocompleteControlBuilder:
public class AutocompleteControlBuilder<C extends AutocompleteControl, B extends AutocompleteControlBuilder<C, B>>
extends MultipleControlBuilder<AutocompleteControl, AutocompleteControlBuilder<C, B>> {
public AutocompleteControlBuilder(final String url,
final AutocompleteType autocompleteType) {
this("", "", url, autocompleteType);
}
public AutocompleteControlBuilder(final String id,
final String caption, final String url,
final AutocompleteType autocompleteType) {
super(id, caption, InputType.AUTOCOMPLETE);
((AutocompleteControl) control).setAutocompleteUrl(url);
((AutocompleteControl) control).setAutocompleteType(autocompleteType);
}
public AutocompleteControlBuilder(final Enum<?> en, final String url,
final AutocompleteType autocompleteType) {
this(en.name(), en.toString(), url, autocompleteType);
}
@Override
protected AutocompleteControl createObj() {
return new AutocompleteControl();
}
@Override
protected AutocompleteControlBuilder<C, B> getThis() {
return this;
}
}
Aber überraschenderweise habe ich einige unerwartete Ergebnisse.
Zum Beispiel in dem folgenden Code habe ich control
zu MultipleControl
werfen Setter trotz der Tatsache zu nennen, dass C extends MultipleControl
...
Darüber hinaus wird der folgende build()
Methodenaufruf: new AutocompleteControlBuilder<AutocompleteControl, AutocompleteControlBuilder>("url", AutocompleteType.STANDARD).build());
kehrt SimpleControl
statt AutocompleteControl
, die nicht macht Sinn, weil ich explizit Typparameter angegeben habe.
Und der letzte Strohhalm ist, dass Prägnanz und klaren Code, den ich versuche zu erreichen, durch hässliche new AutocompleteControlBuilder<AutocompleteControl, AutocompleteControlBuilder>
Konstruktor Anruf getötet werden. Könnte mich jemand auf die besten Praktiken zur Lösung dieses Problems hinweisen?
Darf ich fragen, warum Sie das '' 'builder''' Feld haben? Ich sehe nicht, dass du es benutzt. Java hat bereits kovariante Rückgabetypen, auf den ersten Blick würde ich sagen, dass Sie beide Typparameter entfernen könnten, da beide Implementierungsdetails zu sein scheinen. Es hängt wirklich von der Verwendung ab ... –
Ich habe eine schnelle Frage zu diesem Setup @ mr.nothing, brauchst du eigentlich 'SimpleControl' um nicht-abstrakt zu sein? – EpicPandaForce
Hmm, JavaFX begann auch mit Bauarbeitern und verzichtet heutzutage auf sie. Builder können also stilistische Nachteile haben. In Ihrem Fall: weniger Konstruktoren, eine Factory-Methode in der Steuerelementklasse selbst ('RadioButton.create(). Label (" not me ").build(): ') –