Diese Frage ist subjektiv, aber ich war nur neugierig, wie die meisten Programmierer das angehen. Das folgende Beispiel ist in Pseudo-C #, dies sollte jedoch auch für Java, C ++ und andere OOP-Sprachen gelten.
Wenn ich in meinen Klassen Hilfsmethoden schreibe, neige ich dazu, sie als statisch zu deklarieren und die Felder nur dann zu übergeben, wenn die Hilfsmethode sie benötigt. In Anbetracht des folgenden Codes bevorzuge ich beispielsweise den Methodenaufruf Nr. 2 .
class Foo
{
Bar _bar;
public void DoSomethingWithBar()
{
// Method Call #1.
DoSomethingWithBarImpl();
// Method Call #2.
DoSomethingWithBarImpl(_bar);
}
private void DoSomethingWithBarImpl()
{
_bar.DoSomething();
}
private static void DoSomethingWithBarImpl(Bar bar)
{
bar.DoSomething();
}
}
Mein Grund dafür ist, dass (zumindest für meine Augen) klar wird, dass die Helfer-Methode einen möglichen Nebeneffekt auf andere Objekte hat - auch ohne deren Implementierung zu lesen. Ich stelle fest, dass ich schnell Methoden finden kann, die diese Praxis anwenden und mir so beim Debuggen von Dingen helfen.
Was bevorzugen Sie in Ihrem eigenen Code und was sind Ihre Gründe dafür?
Antworten:
Das hängt wirklich davon ab. Wenn die Werte, mit denen Ihre Helfer arbeiten, primitiv sind, sind statische Methoden eine gute Wahl, wie Péter hervorhob.
Wenn sie komplex sind, dann SOLID gilt, insbesondere die S , die ich und die D .
Beispiel:
Hier geht es um Ihr Problem. Sie können machen
makeEveryBodyAsHappyAsPossible
eine statische Methode, die in den notwendigen Parametern nehmen. Eine andere Option ist:Jetzt
OurHouse
müssen Sie nicht mehr über die Feinheiten der Cookie-Verteilungsregeln Bescheid wissen. Es muss erst jetzt ein Objekt sein, das eine Regel implementiert. Die Implementierung wird in ein Objekt abstrahiert, dessen alleinige Verantwortung darin besteht, die Regel anzuwenden. Dieses Objekt kann isoliert getestet werden.OurHouse
kann mit einem bloßen Schein der getestet werdenCookieDistributor
. Und Sie können leicht entscheiden, die Regeln für die Cookie-Verteilung zu ändern.Achten Sie jedoch darauf, dass Sie es nicht übertreiben. Ein komplexes System von 30 Klassen ist beispielsweise die Implementierung von
CookieDistributor
, bei der jede Klasse nur eine winzige Aufgabe erfüllt, was nicht wirklich Sinn macht. Meine Interpretation des SRP ist, dass es nicht nur vorschreibt, dass jede Klasse nur eine Verantwortung hat, sondern dass eine einzelne Verantwortung von einer einzelnen Klasse ausgeführt werden sollte.Bei Primitiven oder Objekten, die Sie wie Primitive verwenden (z. B. Objekte, die Punkte im Raum, Matrizen oder ähnliches darstellen), sind statische Hilfsklassen sehr sinnvoll. Wenn Sie die Wahl haben und es wirklich sinnvoll ist, können Sie der Klasse, die die Daten darstellt, tatsächlich eine Methode hinzufügen, z. B. ist es sinnvoll
Point
, eineadd
Methode zu haben . Wieder nicht übertreiben.Abhängig von Ihrem Problem gibt es verschiedene Möglichkeiten, dies zu tun.
quelle
Es ist allgemein bekannt, Methoden von Utility-Klassen zu deklarieren
static
, sodass solche Klassen niemals instanziiert werden müssen. Das Befolgen dieser Redewendung erleichtert das Verständnis Ihres Codes, was eine gute Sache ist.Es gibt jedoch eine ernsthafte Einschränkung dieses Ansatzes: Solche Methoden / Klassen können nicht leicht verspottet werden (obwohl AFAIK zumindest für C # Spott-Frameworks gibt, die dies auch erreichen können, aber sie sind nicht alltäglich und zumindest einige von ihnen kommerziell). Also , wenn eine Hilfsmethode hat jede externe Abhängigkeit (zB DB) , die es macht - so seine Anrufer - schwer zu Unit - Test, ist es besser, es nicht statisch zu deklarieren . Dies ermöglicht eine Abhängigkeitsinjektion, wodurch die Aufrufer der Methode leichter einem Komponententest unterzogen werden können.
Aktualisieren
Erläuterung: Die obigen Ausführungen beziehen sich auf Dienstprogrammklassen, die nur Hilfsmethoden auf niedriger Ebene und (normalerweise) keinen Status enthalten. Hilfsmethoden in stateful Nicht-Utility-Klassen sind ein anderes Problem. Entschuldigung für die Fehlinterpretation des OP.
In diesem Fall spüre ich einen Codegeruch: Eine Methode der Klasse A, die in erster Linie auf einer Instanz der Klasse B ausgeführt wird, hat möglicherweise einen besseren Platz in Klasse B. Wenn ich sie jedoch dort belasse, wo sie ist, bevorzuge ich Option 1. da es einfacher und leichter zu lesen ist.
quelle
Ich bevorzuge # 1 (
this->DoSomethingWithBarImpl();
), es sei denn, die Hilfsmethode benötigt natürlich keinen Zugriff auf die Daten / die Implementierung der Instanzstatic t_image OpenDefaultImage()
.öffentliche Schnittstelle und private Implementierung und Mitglieder sind getrennt. Programme wären weitaus schwieriger zu lesen, wenn ich mich für # 2 entschieden hätte. Mit # 1 habe ich immer die Mitglieder und Instanz zur Verfügung. Im Vergleich zu vielen OO-basierten Implementierungen verwende ich in der Regel viel Encapsualtion und nur sehr wenige Member pro Klasse. Was die Nebenwirkungen angeht - damit bin ich einverstanden. Oft gibt es eine Statusüberprüfung, die die Abhängigkeiten erweitert (z. B. Argumente, die übergeben werden müssten).
Nummer 1 ist viel einfacher zu lesen, zu warten und weist gute Leistungsmerkmale auf. Natürlich wird es Fälle geben, in denen Sie eine Implementierung freigeben können:
Wenn Nr. 2 eine gute gemeinsame Lösung (z. B. die Standardlösung) in einer Codebasis wäre, würde mich die Struktur des Designs interessieren: Tun die Klassen zu viel? Gibt es nicht genug Verkapselung oder nicht genug Wiederverwendung? Ist die Abstraktionsstufe hoch genug?
Schließlich scheint # 2 überflüssig zu sein, wenn Sie OO-Sprachen verwenden, bei denen Mutation unterstützt wird (z
const
. B. eine Methode).quelle