Grundsätzlich muss ich unter bestimmten Bedingungen verschiedene Aktionen ausführen. Der vorhandene Code ist so geschrieben
Basisschnittstelle
// DoSomething.java
interface DoSomething {
void letDoIt(String info);
}
Implementierung der ersten Arbeiterklasse
class DoItThisWay implements DoSomething {
...
}
Implementierung der zweiten Arbeiterklasse
class DoItThatWay implements DoSomething {
...
}
Die Hauptklasse
class Main {
public doingIt(String info) {
DoSomething worker;
if (info == 'this') {
worker = new DoItThisWay();
} else {
worker = new DoItThatWay();
}
worker.letDoIt(info)
}
Dieser Code funktioniert einwandfrei und ist leicht zu verstehen.
Jetzt muss ich aufgrund einer neuen Anforderung eine neue Information weitergeben, die nur für sinnvoll ist DoItThisWay
.
Meine Frage ist: Ist der folgende Codierungsstil gut, um mit dieser Anforderung umzugehen.
Verwenden Sie eine neue Klassenvariable und Methode
// Use new class variable and method
class DoItThisWay implements DoSomething {
private int quality;
DoSomething() {
quality = 0;
}
public void setQuality(int quality) {
this.quality = quality;
};
public void letDoIt(String info) {
if (quality > 50) { // make use of the new information
...
} else {
...
}
} ;
}
Wenn ich das so mache, muss ich die entsprechende Änderung am Anrufer vornehmen:
class Main {
public doingIt(String info) {
DoSomething worker;
if (info == 'this') {
int quality = obtainQualityInfo();
DoItThisWay tmp = new DoItThisWay();
tmp.setQuality(quality)
worker = tmp;
} else {
worker = new DoItThatWay();
}
worker.letDoIt(info)
}
Ist es ein guter Codierungsstil? Oder kann ich es einfach besetzen?
class Main {
public doingIt(String info) {
DoSomething worker;
if (info == 'this') {
int quality = obtainQualityInfo();
worker = new DoItThisWay();
((DoItThisWay) worker).setQuality(quality)
} else {
worker = new DoItThatWay();
}
worker.letDoIt(info)
}
java
coding-style
Anthony Kong
quelle
quelle
quality
in den Konstruktor übergehenDoItThisWay
?DoItThisWay
undDoItThatWay
einmalig im Konstruktor von erfolgtMain
.Main
ist eine langlebige Klasse unddoingIt
wird immer wieder aufgerufen.setQuality
Methode während der Lebensdauer desDoItThisWay
Objekts mehrmals aufgerufen wird?Antworten:
Ich gehe davon aus, dass
quality
dies neben jedemletDoIt()
Anruf auf einem gesetzt werden mussDoItThisWay()
.Die Frage , die ich hier sehe entsteht , ist dies: Sie sind die Einführung zeitliche Kopplung (dh was happends wenn Sie anrufen vergessen
setQuality()
vor dem AufrufletDoIt()
auf einDoItThisWay
?). Und die Implementierungen fürDoItThisWay
undDoItThatWay
laufen auseinander (man musssetQuality()
angerufen haben, der andere nicht).Während dies im Moment möglicherweise keine Probleme verursacht, wird es Sie möglicherweise irgendwann verfolgen. Es kann sich lohnen, einen weiteren Blick darauf zu werfen
letDoIt()
und zu prüfen, ob die Qualitätsinformationen Teil der Informationen sein müssen, dieinfo
Sie durchlaufen. das kommt aber auf die details an.quelle
Aus meiner Sicht ist keine Ihrer Versionen. Zuerst muss man anrufen,
setQuality
bevorletDoIt
man angerufen werden kann, ist eine zeitliche Kopplung . Sie stecken beim BetrachtenDoItThisWay
als Derivat von festDoSomething
, aber es ist nicht (zumindest nicht funktional), es ist eher so etwas wie einDas würde
Main
eher so etwas machenAndererseits könnten Sie die Parameter direkt an die Klassen übergeben (sofern dies möglich ist) und die Entscheidung, welche verwendet werden soll, an eine Factory delegieren (dies würde die Instanzen wieder austauschbar machen und beide können abgeleitet werden
DoSomething
). Das würde soMain
aussehenMir ist bewusst, dass Sie das geschrieben haben
Sie können aber auch die Teile zwischenspeichern, die in der Fabrik teuer sind, und sie an den Konstruktor übergeben.
quelle
DoItThisWay
Qualität eingestellt werden muss, bevorletDoIt
es aufgerufen wird, verhält es sich anders. Ich würde erwarten, dass aDoSomething
für alle Derivate auf die gleiche Weise funktioniert (ohne zuvor die Qualität einzustellen). Macht das Sinn? Dies ist natürlich etwas unscharf, dasetQuality
der Kunde , wenn wir die Methode von einer Fabrik aufrufen, nicht weiß, ob die Qualität eingestellt werden muss oder nicht.letDoIt()
lautet (ohne zusätzliche Informationen) "Ich kann alles korrekt ausführen (mache, was ich tue), wenn du es mir gibstString info
". Das vorausgehende AnfordernsetQuality()
eines Anrufs stärkt die Vorbedingung für einen AnrufletDoIt()
und wäre somit eine Verletzung des LSP.letDoIt
" keine Ausnahmen auslösen soll, und das Vergessen, "setQuality" aufzurufenletDoIt
, eine Ausnahme auslösen würde, dann würde ich zustimmen, dass eine solche Implementierung den LSP verletzen würde. Aber diese Annahmen erscheinen mir sehr künstlich.Nehmen wir an, dass
quality
keine Übergabe an den Konstruktor möglich ist und der Aufruf ansetQuality
erforderlich ist.Derzeit mag ein Code-Snippet
ist viel zu klein, um zu viele Gedanken in sie zu investieren. IMHO sieht es ein bisschen hässlich aus, ist aber nicht wirklich schwer zu verstehen.
Probleme treten auf, wenn ein solches Code-Snippet wächst und Sie aufgrund von Umgestaltungen mit so etwas enden
Jetzt sehen Sie nicht sofort, ob dieser Code noch korrekt ist, und der Compiler sagt es Ihnen nicht. Das Einführen einer temporären Variablen des richtigen Typs und das Vermeiden der Umwandlung ist daher ohne großen zusätzlichen Aufwand ein wenig typsicherer.
Allerdings würde ich eigentlich
tmp
einen besseren Namen geben:Eine solche Benennung hilft, falschen Code falsch aussehen zu lassen.
quelle
DoItThisWay
es werden spezifischere Parameter abgerufen - nach Ihren Vorstellungen muss der Name jedes Mal geändert werden. Es ist besser, Namen für Variablen zu verwenden, die den Objekttyp verdeutlichen, nicht die verfügbaren Methodennamen.workerThisWay
so etwas wirdusingQuality
. In diesem kleinen Code-Snippet ist es sicherer, genauer zu sein. (Und wenn es einen besseren Ausdruck in ihrer Domain gibt als "usingQuality", verwenden Sie ihn.Eine allgemeine Schnittstelle, bei der die Initialisierung basierend auf Laufzeitdaten variiert, eignet sich normalerweise für das Factory-Muster.
Dann kann sich DoThingsFactory darum kümmern, die Qualitätsinformationen innerhalb der
getDoer(info)
Methode abzurufen und festzulegen, bevor das konkrete DoThingsWithQuality-Objekt an die DoSomething-Schnittstelle zurückgegeben wird.quelle