Ich arbeite an einem UI-Code, in dem ich eine Action
Klasse habe.
public class MyAction extends Action {
public MyAction() {
setText("My Action Text");
setToolTip("My Action Tool tip");
setImage("Some Image");
}
}
Bei der Erstellung dieser Action-Klasse wurde davon ausgegangen, dass die Action
Klasse nicht anpassbar ist (in gewissem Sinne - der Text, der Tooltip oder das Bild werden an keiner Stelle im Code geändert). Jetzt müssen wir den Aktionstext an einer bestimmten Stelle im Code ändern. Daher schlug ich meinem Kollegen vor, den fest codierten Aktionstext aus dem Konstruktor zu entfernen und als Argument zu akzeptieren, damit jeder gezwungen ist, den Aktionstext zu übergeben. So etwas wie dieser Code unten -
public class MyAction extends Action {
public MyAction(String actionText) {
setText(actionText);
setTooltip("My Action tool tip");
setImage("My Image");
}
}
Er ist jedoch der Ansicht, dass die setText()
Methode , da sie zur Basisklasse gehört, flexibel verwendet werden kann, um den Aktionstext überall dort zu übergeben, wo eine Aktionsinstanz erstellt wird. Auf diese Weise muss die vorhandene MyAction
Klasse nicht geändert werden . Also würde sein Code ungefähr so aussehen.
MyAction action = new MyAction(); //this creates action instance with the hardcoded text
action.setText("User required new action text"); //overwrite the existing text.
Ich bin mir nicht sicher, ob dies der richtige Weg ist, um mit dem Problem umzugehen. Ich denke, in dem oben genannten Fall wird der Benutzer den Text trotzdem ändern. Warum sollte er ihn nicht zwingen, während er die Aktion erstellt? Der einzige Vorteil, den ich mit dem Originalcode sehe, ist, dass der Benutzer eine Action-Klasse erstellen kann, ohne viel über das Festlegen von Text nachdenken zu müssen.
Antworten:
Das ist eigentlich kein Vorteil, für die meisten Zwecke ist es ein Nachteil und in den übrigen Fällen würde ich es als Gleichstand bezeichnen. Was passiert, wenn jemand vergisst, setText () nach der Erstellung aufzurufen? Was ist, wenn dies in einem ungewöhnlichen Fall der Fall ist, vielleicht ein Fehlerbehandler? Wenn Sie das Festlegen des Texts wirklich erzwingen möchten, müssen Sie es beim Kompilieren erzwingen, da nur Fehler beim Kompilieren tatsächlich schwerwiegend sind . Alles, was zur Laufzeit passiert, hängt von dem jeweiligen Codepfad ab, der ausgeführt wird.
Ich sehe zwei klare Wege vorwärts:
null
eine leere Zeichenfolge übergeben, aber die Tatsache, dass Sie keinen Text zuweisen, ist eher explizit als implizit. Es ist einfach, die Existenz einesnull
Parameters zu erkennen und zu sehen, dass möglicherweise einige Überlegungen angestellt wurden, aber nicht so einfach, das Fehlen eines Methodenaufrufs zu erkennen und festzustellen, ob das Fehlen eines solchen beabsichtigt war oder nicht. Für einen einfachen Fall wie diesen ist dies wahrscheinlich der Ansatz, den ich wählen würde.quelle
Konstruktorüberladung wäre hier eine einfache und unkomplizierte Lösung:
Es ist besser als
.setText
später anzurufen , da auf diese Weise nichts überschrieben werden muss,actionText
was von Anfang an beabsichtigt sein kann.Wenn sich Ihr Code weiterentwickelt und Sie noch mehr Flexibilität benötigen (was sicherlich passieren wird), profitieren Sie von dem Factory / Builder-Muster, das in einer anderen Antwort vorgeschlagen wird.
quelle
Fügen Sie eine fließende 'setText'-Methode hinzu:
Was könnte klarer sein als das? Wenn Sie eine weitere anpassbare Eigenschaft hinzufügen möchten, ist dies kein Problem.
quelle
setText()
Wenn Sie sich jedoch das spezifische Beispiel in dieser Frage ansehen, vermute ich, dass es für die Action-Klasse definiert ist, von der MyAction erbt. Es hat wahrscheinlich bereits einen ungültigen Rückgabetyp.Genau wie Kevin Cline in seiner Antwort sagte, denke ich, dass der Weg dahin darin besteht, eine flüssige API zu erstellen . Ich möchte nur hinzufügen, dass die flüssige API besser funktioniert, wenn Sie mehr als eine Eigenschaft haben, die Sie möglicherweise verwenden.
Es wird Ihren Code besser lesbar, und aus meiner Sicht einfacher und macht aham , „sexy“ zu schreiben.
In Ihrem Fall würde es so verlaufen (Entschuldigung für einen Tippfehler, es ist ein Jahr her, seit ich mein letztes Java-Programm geschrieben habe):
Und die Verwendung wäre wie folgt:
quelle
Der Rat, Konstrukteure oder Bauherren zu verwenden, ist im Allgemeinen in Ordnung, aber meiner Erfahrung nach fehlen einige wichtige Punkte für Aktionen, die
Es wird dringend empfohlen, den Namen, den Tooltip, das Symbol usw. aus einer Eigenschaftendatei, XML usw. zu lesen. Für die Aktion "Datei öffnen" könnten Sie beispielsweise Eigenschaften übergeben, nach denen gesucht wird
Dies ist ein Format, das ziemlich einfach ins Französische zu übersetzen ist, um ein neues besseres Symbol auszuprobieren usw. Ohne Programmiererzeit oder Neukompilierung.
Dies ist nur ein grober Abriss, dem Leser bleibt viel übrig ... Suchen Sie nach anderen Beispielen für Internationalisierung.
quelle
Es ist sinnlos, setText (actionText) oder setTooltip ("My action tool tip") im Konstruktor aufzurufen. Es ist einfacher (und Sie erzielen mehr Leistung), wenn Sie das entsprechende Feld direkt initialisieren:
Wenn Sie actionText während der Lebensdauer des MyAction-entsprechenden Objekts ändern, sollten Sie eine Setter-Methode platzieren. Wenn nicht, initialisieren Sie das Feld nur im Konstruktor, ohne eine Setter-Methode anzugeben.
Da QuickInfo und Bild Konstanten sind, behandeln Sie sie als Konstanten. Felder haben:
Tatsächlich ist es beim Entwerfen allgemeiner Objekte (keine Beans oder Objekte, die ausschließlich Datenstrukturen darstellen) eine schlechte Idee, Setter und Getter bereitzustellen, da diese die Kapselung aufheben.
quelle
Ich denke, dass dies zutrifft, wenn wir eine allgemeine Aktionsklasse erstellen (wie update, die zum Aktualisieren von Employee, Department ... verwendet wird). Es hängt alles vom Szenario ab. Wenn eine bestimmte Aktionsklasse (z. B. "Mitarbeiter aktualisieren") (die an vielen Stellen in der Anwendung verwendet wird - Mitarbeiter aktualisieren) mit der Absicht erstellt wird, an jeder Stelle in der Anwendung denselben Text, dieselbe QuickInfo und dasselbe Bild beizubehalten (aus Gründen der Konsistenz). So können Texte, QuickInfos und Bilder hartcodiert werden, um die Standardtexte, QuickInfos und Bilder bereitzustellen. Um noch mehr Flexibilität zu bieten und diese anzupassen, sollte es entsprechende Setter-Methoden geben. Wenn wir nur 10% der Stellen im Kopf behalten, müssen wir sie ändern. Wenn der Benutzer jedes Mal einen Aktionstext entgegennimmt, kann dies jedes Mal zu einem anderen Text für dieselbe Aktion führen. Wie 'Update Emp', 'Update Employee', 'Change Employee' oder 'Edit Employee'.
quelle
Überlegen Sie, wie Instanzen verwendet werden, und verwenden Sie eine Lösung, die die Benutzer anleitet oder sogar zwingt, diese Instanzen auf die richtige oder zumindest beste Weise zu verwenden. Ein Programmierer, der diese Klasse verwendet, muss sich über viele andere Dinge Gedanken machen. Diese Klasse sollte nicht zur Liste hinzugefügt werden.
Wenn die MyAction-Klasse beispielsweise nach der Erstellung (und möglicherweise nach einer anderen Initialisierung) unveränderlich sein soll, sollte sie keine Setter-Methode haben. Wenn die meiste Zeit der Standard "Mein Aktionstext" verwendet wird, sollte es einen parameterlosen Konstruktor sowie einen Konstruktor geben, der optionalen Text zulässt. Jetzt muss der Benutzer nicht mehr darüber nachdenken, die Klasse in 90% der Fälle korrekt zu verwenden. Wenn der Benutzer in der Regel sollte sich Gedanken über den Text geben, lassen Sie die parameterlosen Konstruktor. Jetzt muss der Benutzer nachdenken, wenn es nötig ist, und kann einen notwendigen Schritt nicht übersehen.
Wenn eine
MyAction
Instanz nach der vollständigen Erstellung veränderbar sein soll, benötigen Sie einen Setter für den Text. Es ist verlockend, das Setzen des Wertes im Konstruktor zu überspringen (DRY-Prinzip - "Wiederholen Sie sich nicht"), und wenn der Standardwert normalerweise gut genug ist, würde ich das tun. Wenn dies nicht der Fall ist, wird der Benutzer durch die Anforderung des Textes im Konstruktor gezwungen, zu überlegen, wann er sollte.Beachten Sie, dass diese Benutzer nicht dumm sind . Sie haben einfach zu viele echte Probleme, um die sie sich Sorgen machen müssen. Indem Sie über die "Schnittstelle" Ihrer Klasse nachdenken, können Sie verhindern, dass diese auch zu einem echten Problem wird - und zu einem unnötigen.
quelle
In der folgenden vorgeschlagenen Lösung ist die Superklasse abstrakt und für alle drei Elemente ist ein Standardwert festgelegt.
Die Unterklasse hat verschiedene Konstruktoren, so dass der Programmierer sie instanziieren kann.
Wenn der erste Konstruktor verwendet wird, haben alle Member die Standardwerte.
Wenn der zweite Konstruktor verwendet wird, geben Sie dem actionText-Member einen Anfangswert und lassen die anderen beiden Member mit dem Standardwert ...
Wenn der dritte Konstruktor verwendet wird, instanziieren Sie ihn mit einem neuen Wert für actionText und toolTip, wobei imageURl mit dem Standardwert belassen wird ...
Und so weiter.
quelle