Ich habe eine Klasse, die ein Array von Knoten erstellt und diese in einer grafischen Struktur miteinander verbindet. Ist es am besten zu:
- Behalten Sie die Funktionalität bei, um die Knoten in einer Funktion zu initialisieren und zu verbinden
- Haben Sie die Initialisierungs- und Verbindungsfunktionalität in zwei verschiedenen Funktionen (und haben Sie eine abhängige Reihenfolge, in der die Funktionen aufgerufen werden müssen - beachten Sie jedoch, dass diese Funktionen privat sind.)
Methode 1: (Schlecht darin, dass eine Funktion zwei Dinge ausführt, ABER die abhängige Funktionalität bleibt in Gruppen zusammengefasst - die Knoten sollten niemals ohne vorherige Initialisierung verbunden werden.)
init() {
setupNodes()
}
private func setupNodes() {
// 1. Create array of nodes
// 2. Go through array, connecting each node to its neighbors
// according to some predefined constants
}
Methode 2: (Besser in dem Sinne, dass es selbstdokumentierend ist, ABER connectNodes () sollte niemals vor setupNodes () aufgerufen werden, daher muss jeder, der mit den Klasseninternalen arbeitet, über diese Reihenfolge Bescheid wissen.)
init() {
setupNodes()
}
private func setupNodes() {
createNodes()
connectNodes()
}
private func createNodes() {
// 1. Create array of nodes
}
private func connectNodes() {
// 2. Go through array, connecting each node to its neighbors
// according to some predefined constants
}
Aufgeregt, irgendwelche Gedanken zu hören.
Antworten:
Das Problem, mit dem Sie sich beschäftigen, heißt zeitliche Kopplung
Sie sind zu Recht besorgt darüber, wie verständlich dieser Code ist:
Ich kann mir vorstellen, was dort vor sich geht, aber sagen Sie mir, ob dies etwas klarer macht, was sonst noch vor sich geht:
Dies hat den zusätzlichen Vorteil, dass es weniger mit dem Ändern von Instanzvariablen verbunden ist, aber für mich ist Lesbarkeit die Nummer eins.
Dies macht
connectNodes()
die Abhängigkeit von Knoten explizit.quelle
Getrennte Funktionen aus zwei Gründen:
1. Private Funktionen sind für genau diese Situation privat.Ihre
init
Funktion ist öffentlich und die Schnittstelle, das Verhalten und der Rückgabewert müssen Sie schützen und ändern. Das Ergebnis, das Sie von dieser Methode erwarten, wird unabhängig von der verwendeten Implementierung dasselbe sein.Da sich der Rest der Funktionalität hinter diesem privaten Schlüsselwort verbirgt, kann es nach Belieben implementiert werden. Sie können es also auch schön und modular gestalten, selbst wenn ein Bit davon abhängt, dass das andere zuerst aufgerufen wird.
2. Das Verbinden von Knoten untereinander ist möglicherweise keine private FunktionWas ist, wenn Sie dem Array irgendwann andere Knoten hinzufügen möchten? Zerstören Sie das Setup, das Sie jetzt haben, und initialisieren Sie es vollständig neu? Oder fügen Sie dem vorhandenen Array Knoten hinzu und führen Sie es
connectNodes
erneut aus?Möglicherweise
connectNodes
kann es zu einer vernünftigen Reaktion kommen, wenn das Knotenarray noch nicht erstellt wurde (eine Ausnahme auslösen, eine leere Menge zurückgeben, entscheiden, was für Ihre Situation sinnvoll ist).quelle
Sie werden möglicherweise auch feststellen (je nachdem, wie komplex jede dieser Aufgaben ist), dass dies eine gute Naht ist, um eine andere Klasse aufzuteilen.
(Ich bin mir nicht sicher, ob Swift so funktioniert, aber Pseudocode :)
Dies trennt die Zuständigkeiten beim Erstellen und Ändern von Knoten zu separaten Klassen: Es geht
NodeGenerator
nur um das Erstellen / Abrufen von Knoten, während esYourClass
nur um das Verbinden der Knoten geht, die angegeben sind.quelle
Swift ist nicht nur der genaue Zweck privater Methoden, sondern bietet Ihnen auch die Möglichkeit, innere Funktionen zu verwenden.
Innere Methoden sind perfekt für Funktionen, die nur eine einzige Aufrufstelle haben, aber das Gefühl haben, dass sie keine separaten privaten Funktionen rechtfertigen.
Beispielsweise ist es sehr verbreitet, eine öffentliche rekursive "Eingabe" -Funktion zu haben, die die Voraussetzungen überprüft, einige Parameter einrichtet und an eine private rekursive Funktion delegiert, die die Arbeit erledigt.
Hier ist ein Beispiel, wie das in diesem Fall aussehen könnte:
Achten Sie darauf, wie ich Rückgabewerte und Parameter verwende, um Daten weiterzugeben, anstatt einen gemeinsam genutzten Status zu ändern. Dadurch wird der Datenfluss auf den ersten Blick viel deutlicher, ohne dass Sie in die Implementierung einsteigen müssen.
quelle
Jede Funktion, die Sie deklarieren, ist mit dem Hinzufügen und Verallgemeinern von Dokumentation verbunden, damit sie von anderen Programmteilen verwendet werden kann. Es muss auch verstanden werden, wie andere Funktionen in der Datei sie möglicherweise für jemanden verwenden, der den Code liest.
Wenn es jedoch nicht von anderen Teilen Ihres Programms verwendet wird, würde ich es nicht als separate Funktion verfügbar machen.
Wenn Ihre Sprache dies unterstützt, können Sie mithilfe verschachtelter Funktionen immer noch eine Funktion ausführen
Der Ort der Deklaration ist sehr wichtig, und im obigen Beispiel ist klar, ohne dass weitere Hinweise erforderlich sind, dass die inneren Funktionen nur innerhalb des Körpers der äußeren Funktion verwendet werden sollen.
Selbst wenn Sie sie als private Funktionen deklarieren, gehe ich davon aus, dass sie weiterhin für die gesamte Datei sichtbar sind. Sie müssten sie also in der Nähe der Deklaration der Hauptfunktion deklarieren und eine Dokumentation hinzufügen, die klarstellt, dass sie nur von der äußeren Funktion verwendet werden dürfen.
Ich glaube nicht, dass Sie das eine oder andere unbedingt tun müssen. Das Beste, was Sie tun können, ist von Fall zu Fall unterschiedlich.
Das Aufteilen in mehrere Funktionen erhöht den Aufwand für das Verständnis, warum es drei Funktionen gibt und wie sie alle miteinander arbeiten. Wenn die Logik jedoch komplex ist, ist der zusätzliche Aufwand möglicherweise viel geringer als die Einfachheit, die durch das Aufteilen der komplexen Logik entsteht in einfachere Teile.
quelle
private
Erlaubt den Zugriff nur innerhalb des einschließenden Typs (struct / class / enum), währendfileprivate
der Zugriff in der gesamten Datei erlaubt ist