Es fällt mir oft schwer zu entscheiden, welche dieser beiden Methoden ich verwenden soll, wenn ich gemeinsame Daten für einige Methoden in meinen Klassen verwenden möchte. Was wäre eine bessere Wahl?
Mit dieser Option kann ich eine Instanzvariable erstellen, um zu vermeiden, dass zusätzliche Variablen deklariert werden müssen, und um auch die Definition von Methodenparametern zu vermeiden. Es ist jedoch möglicherweise nicht klar, wo diese Variablen instanziiert / geändert werden:
public class MyClass {
private int var1;
MyClass(){
doSomething();
doSomethingElse();
doMoreStuff();
}
private void doSomething(){
var1 = 2;
}
private void doSomethingElse(){
int var2 = var1 + 1;
}
private void doMoreStuff(){
int var3 = var1 - 1;
}
}
Oder einfach nur lokale Variablen instanziieren und als Argumente übergeben?
public class MyClass {
MyClass(){
int var1 = doSomething();
doSomethingElse(var1);
doMoreStuff(var1);
}
private int doSomething(){
int var = 2;
return var;
}
private void doSomethingElse(int var){
int var2 = var + 1;
}
private void doMoreStuff(int var){
int var3 = var - 1;
}
}
Wenn die Antwort lautet, dass beide richtig sind, welche wird dann häufiger gesehen / verwendet? Auch wenn Sie zusätzliche Vor- / Nachteile für jede Option angeben können, wäre dies sehr wertvoll.
quelle
Antworten:
Ich bin überrascht, dass dies noch nicht erwähnt wurde ...
Es hängt davon ab, ob
var1
es sich tatsächlich um einen Teil des Status Ihres Objekts handelt .Sie gehen davon aus, dass beide Ansätze korrekt sind und dass es nur um Stil geht. Sie liegen falsch.
Hier geht es ausschließlich darum, wie man richtig modelliert.
In ähnlicher Weise gibt es
private
Instanzmethoden, um den Status Ihres Objekts zu ändern . Wenn Ihre Methode dies nicht tut, sollte es so seinprivate static
.quelle
transient
hat nichts damit zu tun, datransient
es sich um einen dauerhaften Zustand handelt, wie in Teilen des Objekts, die gespeichert werden, wenn Sie so etwas wie das Objekt serialisieren. Beispielsweise ist der Sicherungsspeicher einer ArrayList vontransient
entscheidender Bedeutung für den Zustand der ArrayList, da Sie beim Serialisieren einer ArrayList nur den Teil des Sicherungsspeichers speichern möchten, der die tatsächlichen ArrayList-Elemente enthält, nicht den freien Speicherplatz am Ende reserviert für weitere Elementzusätze.var1
für ein paar Methoden benötigt wird, aber nicht zum Status von gehörtMyClass
, ist es möglicherweise an der Zeit,var1
diese Methoden in eine andere Klasse einzufügen, die von verwendet werden sollMyClass
.Ich weiß nicht, was häufiger vorkommt, aber ich würde immer Letzteres tun. Es kommuniziert den Datenfluss und die Lebensdauer klarer und bläht nicht jede Instanz Ihrer Klasse mit einem Feld auf, dessen einzige relevante Lebensdauer bei der Initialisierung liegt. Ich würde sagen, dass Ersteres nur verwirrend ist und die Codeüberprüfung erheblich erschwert, da ich die Möglichkeit in Betracht ziehen muss, dass eine Methode möglicherweise geändert wird
var1
.quelle
Sie sollten den Umfang Ihrer Variablen so weit wie möglich (und sinnvoll) reduzieren . Nicht nur in Methoden, sondern allgemein.
Für Ihre Frage bedeutet dies, dass es davon abhängt, ob die Variable Teil des Objektstatus ist. Wenn ja, ist es in Ordnung, es in diesem Bereich zu verwenden, dh das gesamte Objekt. In diesem Fall wählen Sie die erste Option. Wenn nicht, wählen Sie die zweite Option, da sie die Sichtbarkeit von Variablen und damit die Gesamtkomplexität verringert.
quelle
Es gibt noch einen anderen Stil - benutze einen Kontext / Zustand.
Dieser Ansatz bietet eine Reihe von Vorteilen. Die Zustandsobjekte können sich beispielsweise unabhängig vom Objekt ändern, was viel Spielraum für die Zukunft bietet.
Dies ist ein Muster, das auch in einem verteilten / Server-System gut funktioniert, in dem einige Details über Aufrufe hinweg beibehalten werden müssen. Sie können Benutzerdetails, Datenbankverbindungen usw. im
state
Objekt speichern .quelle
Es geht um Nebenwirkungen.
Die Frage, ob
var1
ein Teil des Staates ist, verfehlt den Punkt dieser Frage. Sicher, wennvar1
es bestehen bleiben muss, muss es eine Instanz sein. Beide Ansätze können angewendet werden, um zu funktionieren, ob Persistenz erforderlich ist oder nicht.Der Nebenwirkungsansatz
Einige Instanzvariablen werden nur zur Kommunikation zwischen privaten Methoden von Aufruf zu Aufruf verwendet. Diese Art von Instanzvariable kann aus der Existenz heraus überarbeitet werden, muss es aber nicht sein. Manchmal sind die Dinge mit ihnen klarer. Dies ist jedoch nicht ohne Risiko.
Sie lassen eine Variable aus ihrem Bereich heraus, da sie in zwei verschiedenen privaten Bereichen verwendet wird. Nicht, weil es in dem Bereich benötigt wird, in dem Sie es platzieren. Das kann verwirrend sein. Die "Globalen sind böse!" Grad der Verwirrung. Das kann funktionieren, ist aber nicht gut skalierbar. Es funktioniert nur im Kleinen. Keine großen Gegenstände. Keine langen Vererbungsketten. Verursacht keinen Jojo- Effekt.
Der funktionale Ansatz
Nun, auch wenn
var1
nichts bestehen bleiben muss , müssen Sie verwenden, wenn für jeden Übergangswert, den er annehmen könnte, bevor er den Zustand erreicht, den Sie zwischen öffentlichen Aufrufen beibehalten möchten. Das heißt, Sie können einevar1
Instanz immer noch mit nur funktionaleren Methoden festlegen .So Teil des Staates oder nicht, können Sie noch einen der beiden Ansätze verwenden.
In diesen Beispielen ist 'var1' so gekapselt, dass nichts anderes als Ihr Debugger weiß, dass es existiert. Ich vermute, Sie haben das absichtlich getan, weil Sie uns nicht voreingenommen machen wollen. Zum Glück ist mir egal welche.
Das Risiko von Nebenwirkungen
Das heißt, ich weiß, wo Ihre Frage herkommt. Ich habe unter miserablen gearbeitet yo yo ‚ing Erbe , das mutiert eine Instanzvariable auf mehreren Ebenen in mehreren Methoden und squirrelly gegangenes versuchen , ihm zu folgen. Das ist das Risiko.
Dies ist der Schmerz, der mich zu einem funktionaleren Ansatz treibt. Eine Methode kann ihre Abhängigkeiten dokumentieren und in ihrer Signatur ausgeben. Dies ist ein kraftvoller, klarer Ansatz. Sie können damit auch ändern, was Sie an der privaten Methode übergeben, sodass diese innerhalb der Klasse wiederverwendbarer ist.
Die Vorteile von Nebenwirkungen
Es ist auch einschränkend. Reine Funktionen haben keine Nebenwirkungen. Das kann eine gute Sache sein, ist aber nicht objektorientiert. Ein großer Teil der Objektorientierung ist die Fähigkeit, sich auf einen Kontext außerhalb der Methode zu beziehen. Es ist die Stärke von OOP, dies zu tun, ohne dass die Globalen hier und da auslaufen. Ich bekomme die Flexibilität eines globalen, aber es ist schön in der Klasse enthalten. Ich kann eine Methode aufrufen und jede Instanzvariable auf einmal ändern, wenn ich möchte. Wenn ich das tue, bin ich verpflichtet, der Methode zumindest einen Namen zu geben, der klar macht, worum es geht, damit die Leute nicht überrascht werden, wenn das passiert. Kommentare können ebenfalls hilfreich sein. Manchmal werden diese Kommentare als "Beitragsbedingungen" formalisiert.
Der Nachteil funktionaler privater Methoden
Der funktionale Ansatz macht einige Abhängigkeiten deutlich. Sofern Sie nicht in einer reinen funktionalen Sprache arbeiten, können versteckte Abhängigkeiten nicht ausgeschlossen werden. Wenn Sie sich nur eine Methodensignatur ansehen, wissen Sie nicht, dass sie im Rest des Codes keinen Nebeneffekt vor Ihnen verbirgt. Das tust du einfach nicht.
Post Bedingungen
Wenn Sie und alle anderen Mitglieder des Teams die Nebenwirkungen (vor / nach den Bedingungen) zuverlässig in Kommentaren dokumentieren, ist der Nutzen aus dem funktionalen Ansatz viel geringer. Ja, ich weiß, träume weiter.
Fazit
Persönlich tendiere ich in beiden Fällen zu funktionalen privaten Methoden, wenn ich kann, aber ehrlich gesagt, hauptsächlich, weil diese vor / nach-bedingten Nebenwirkungskommentare keine Compilerfehler verursachen, wenn sie veraltet sind oder wenn Methoden nicht in der richtigen Reihenfolge aufgerufen werden. Wenn ich nicht wirklich die Flexibilität von Nebenwirkungen brauche, möchte ich lieber nur wissen, dass die Dinge funktionieren.
quelle
var1
durch einen Paradigmenwechsel das Speichern als Zustandsvariable vermeiden können . Der Klassenbereich ist NICHT nur dort, wo der Status gespeichert ist. Es ist auch ein umschließender Bereich. Das bedeutet, dass es zwei mögliche Gründe gibt, eine Variable auf Klassenebene zu setzen. Sie können behaupten, dies nur für den umschließenden Bereich zu tun und nicht, dass der Staat böse ist, aber ich sage, es ist ein Kompromiss mit der Arität, die auch böse ist. Ich weiß das, weil ich Code pflegen musste, der dies tut. Einige waren gut gemacht. Einige waren ein Albtraum. Die Linie zwischen den beiden ist kein Zustand. Es ist die Lesbarkeit.Die erste Variante sieht für mich nicht intuitiv und möglicherweise gefährlich aus (stellen Sie sich aus irgendeinem Grund vor, jemand macht Ihre private Methode öffentlich).
Ich würde Ihre Variablen viel lieber bei der Klassenkonstruktion instanziieren oder als Argumente übergeben. Letzteres bietet Ihnen die Möglichkeit, funktionale Redewendungen zu verwenden und sich nicht auf den Zustand des enthaltenen Objekts zu verlassen.
quelle
Es gibt bereits Antworten zum Objektstatus und wann die zweite Methode bevorzugt wird. Ich möchte nur einen allgemeinen Anwendungsfall für das erste Muster hinzufügen.
Das erste Muster ist vollkommen gültig, wenn Ihre Klasse lediglich einen Algorithmus kapselt . Ein Anwendungsfall hierfür ist, dass der Algorithmus zu groß wäre, wenn Sie ihn auf eine einzige Methode schreiben würden. Sie unterteilen es also in kleinere Methoden, machen es zu einer Klasse und machen die Untermethoden privat.
Wenn Sie nun den gesamten Status des Algorithmus über Parameter übergeben, wird dies möglicherweise mühsam, sodass Sie die privaten Felder verwenden. Es stimmt auch mit der Regel im ersten Absatz überein, da es im Grunde genommen ein Zustand der Instanz ist. Sie müssen nur bedenken und richtig dokumentieren, dass der Algorithmus nicht wiedereintrittsfähig ist, wenn Sie dafür private Felder verwenden . Dies sollte die meiste Zeit kein Problem sein, kann Sie aber möglicherweise beißen.
quelle
Lassen Sie uns ein Beispiel ausprobieren, das etwas bewirkt. Verzeih mir, das ist Javascript, nicht Java. Der Punkt sollte der gleiche sein.
Besuchen Sie https://blockly-games.appspot.com/pond-duck?lang=de , klicken Sie auf die Registerkarte Javascript und fügen Sie Folgendes ein:
Sie sollten feststellen , dass
dir
,wid
unddis
nicht um eine Menge geführt zu werden . Sie sollten auch beachten, dass der Code in der Funktion, dielock()
zurückgibt, einem Pseudocode ähnelt. Nun, es ist tatsächlicher Code. Trotzdem ist es sehr leicht zu lesen. Wir könnten Übergabe und Zuweisung hinzufügen, aber das würde Unordnung hinzufügen, die Sie niemals im Pseudocode sehen würden.Wenn Sie argumentieren möchten, dass es in Ordnung ist, das Zuweisen und Übergeben nicht durchzuführen, da diese drei Variablen einen beständigen Status aufweisen, sollten Sie ein Redesign in Betracht ziehen,
dir
bei dem jeder Schleife ein zufälliger Wert zugewiesen wird. Nicht beständig jetzt, oder?Sicher, jetzt könnten wir den
dir
Umfang verringern, aber nicht ohne gezwungen zu sein, unseren Pseudo-ähnlichen Code mit Übergabe und Einstellung zu überfrachten.Nein, der Status ist nicht der Grund, warum Sie sich entscheiden, Nebenwirkungen zu verwenden oder nicht zu verwenden, anstatt zu bestehen und zurückzukehren. Weder bedeuten Nebenwirkungen allein, dass Ihr Code nicht lesbar ist. Sie profitieren nicht von reinem Funktionscode . Aber gut gemacht, mit guten Namen, können sie tatsächlich schön zu lesen sein.
Das soll nicht heißen, dass sie sich nicht in einen Spaghetti wie einen Albtraum verwandeln können. Aber was kann das nicht?
Fröhliche Entenjagd.
quelle