Wenn ich große Methoden (oder Prozeduren oder Funktionen ) in viele kleine aufspalte, ist diese Frage nicht OOP-spezifisch, aber da ich 99% der Zeit in OOP-Sprachen arbeite, ist es die Terminologie, mit der ich mich am wohlsten fühle Ich finde mich oft mit den Ergebnissen unzufrieden. Es wird schwieriger, über diese kleinen Methoden nachzudenken, als wenn sie nur Codeblöcke in der großen waren, da ich beim Extrahieren viele zugrunde liegende Annahmen verliere, die aus dem Kontext des Aufrufers stammen.
Wenn ich später diesen Code betrachte und einzelne Methoden sehe, weiß ich nicht sofort, woher sie aufgerufen werden, und stelle sie mir als gewöhnliche private Methoden vor, die von einer beliebigen Stelle in der Datei aus aufgerufen werden können. Stellen Sie sich zum Beispiel eine Initialisierungsmethode (Konstruktor oder auf andere Weise) vor, die in eine Reihe kleinerer Methoden aufgeteilt ist: Im Kontext der Methode selbst wissen Sie eindeutig, dass der Status des Objekts immer noch ungültig ist, aber bei einer normalen privaten Methode gehen Sie wahrscheinlich von der Annahme dieses Objekts aus ist bereits initialisiert und befindet sich in einem gültigen Zustand.
Die einzige Lösung, die ich dafür gesehen habe, ist die where
Klausel in Haskell, mit der Sie kleine Funktionen definieren können, die nur in der übergeordneten Funktion verwendet werden. Grundsätzlich sieht es so aus:
len x y = sqrt $ (sq x) + (sq y)
where sq a = a * a
Aber andere Sprachen, die ich verwende, haben so etwas nicht - am nächsten kommt es darauf an, ein Lambda in einem lokalen Bereich zu definieren, was wahrscheinlich noch verwirrender ist.
Meine Frage lautet also: Stoßen Sie darauf und sehen Sie überhaupt, dass dies ein Problem ist? Wie lösen Sie das Problem normalerweise, insbesondere in "Mainstream" -OOP-Sprachen wie Java / C # / C ++?
Bearbeiten von Duplikaten: Wie andere bemerkt haben, gibt es bereits Fragen zu Aufteilungsmethoden und kleinen Fragen, die einzeilig sind. Ich habe sie gelesen und sie diskutieren nicht das Problem der zugrunde liegenden Annahmen , die aus dem Kontext des Aufrufers abgeleitet werden können (im obigen Beispiel wird das Objekt initialisiert). Das ist der Punkt meiner Frage, und deshalb ist meine Frage anders.
Update: Wenn Sie dieser Frage und der folgenden Diskussion gefolgt sind, könnte Ihnen dieser Artikel von John Carmack zu diesem Thema gefallen , insbesondere:
Inlining-Funktionen kennen nicht nur den Code, der gerade ausgeführt wird, sondern haben auch den Vorteil, dass sie nicht von anderen Stellen aus aufgerufen werden können. Das klingt lächerlich, hat aber einen Sinn. Wenn eine Codebasis im Laufe der Jahre wächst, gibt es viele Möglichkeiten, eine Verknüpfung zu erstellen und eine Funktion aufzurufen, die nur die Arbeit leistet, die Ihrer Meinung nach erledigt werden muss. Möglicherweise gibt es eine FullUpdate () - Funktion, die PartialUpdateA () und PartialUpdateB () aufruft. In bestimmten Fällen stellen Sie jedoch möglicherweise fest (oder denken), dass Sie nur PartialUpdateB () ausführen müssen, und Sie sind effizient, indem Sie die andere Funktion vermeiden Arbeit. Daraus resultieren viele, viele Bugs. Die meisten Fehler sind darauf zurückzuführen, dass der Ausführungsstatus nicht genau dem entspricht, was Sie denken.