Ich habe kürzlich einige statische "Utility Bag" -Klassen im Helper-Stil überprüft, die in einigen großen C # -Codebasen schweben, mit denen ich arbeite. Grundsätzlich Dinge wie das folgende sehr komprimierte Snippet:
// Helpers.cs
public static class Helpers
{
public static void DoSomething() {}
public static void DoSomethingElse() {}
}
Die spezifischen Methoden, die ich überprüft habe, sind
- meist nicht miteinander verwandt,
- ohne expliziten Zustand über Aufrufe bestanden,
- klein und
- jeweils von einer Vielzahl von nicht verwandten Typen konsumiert.
Bearbeiten: Das oben Gesagte ist nicht als Liste angeblicher Probleme gedacht. Es ist eine Liste allgemeiner Merkmale der spezifischen Methoden, die ich überprüfe. Es ist ein Kontext, der Antworten hilft, relevantere Lösungen bereitzustellen.
Nur für diese Frage werde ich diese Art von Methode als GLUM (General Lightweight Utility Method) bezeichnen. Die negative Konnotation von "bedrückt" ist teilweise beabsichtigt. Es tut mir leid, wenn dies als dummes Wortspiel rüberkommt.
Selbst wenn ich meine Standard-Skepsis gegenüber GLUMs beiseite lasse, mag ich die folgenden Dinge nicht:
- Eine statische Klasse wird ausschließlich als Namespace verwendet.
- Die statische Klassenkennung ist grundsätzlich bedeutungslos.
- Wenn ein neues GLUM hinzugefügt wird, wird entweder (a) diese "Taschen" -Klasse ohne guten Grund berührt oder (b) eine neue "Taschen" -Klasse erstellt (was an sich normalerweise kein Problem darstellt; was schlecht ist, ist, dass die neue statische Klassen wiederholen oft nur das Problem der Nicht-Verwandtschaft, jedoch mit weniger Methoden.
- Die Meta-Namensgebung ist unentrinnbar schrecklich, Nicht-Standard, und in der Regel intern inkonsistent, wäre es
Helpers
,Utilities
oder was auch immer.
Was ist ein einigermaßen gutes und einfaches Muster, um dies umzugestalten, vorzugsweise die oben genannten Bedenken auszuräumen und vorzugsweise mit einer möglichst leichten Berührung?
Ich sollte wahrscheinlich betonen: Alle Methoden, mit denen ich zu tun habe, sind paarweise nicht miteinander verbunden. Es scheint keinen vernünftigen Weg zu geben, sie in feinkörnigere und dennoch mehrköpfige Methodenbeutel für statische Klassen zu zerlegen.
quelle
Antworten:
Ich denke, Sie haben zwei Probleme, die eng miteinander verbunden sind.
Diese Probleme können behoben werden, indem nur logisch verwandte Methoden in einer statischen Klasse kombiniert und die anderen in ihre eigene statische Klasse verschoben werden. Basierend auf Ihrer Problemdomäne sollten Sie und Ihr Team entscheiden, nach welchen Kriterien Sie Methoden in verwandte statische Klassen unterteilen.
Bedenken und mögliche Lösungen
Methoden sind meist nicht miteinander verbunden - Problem. Kombinieren Sie verwandte Methoden unter einer statischen Klasse und verschieben Sie nicht verwandte Methoden in ihre eigenen statischen Klassen.
Methoden werden ohne expliziten Status über Aufrufe hinweg beibehalten - kein Problem. Zustandslose Methoden sind eine Funktion, kein Fehler. Der statische Status ist ohnehin schwer zu testen und sollte nur verwendet werden, wenn Sie den Status über Methodenaufrufe hinweg beibehalten müssen. Es gibt jedoch bessere Möglichkeiten, dies zu tun, z. B. Statusmaschinen und das
yield
Schlüsselwort.Methoden sind klein - kein Problem. - Methoden sollten klein sein.
Methoden werden jeweils von einer Vielzahl nicht verwandter Typen konsumiert - kein Problem. Sie haben eine allgemeine Methode erstellt, die an vielen nicht verwandten Stellen wiederverwendet werden kann.
Eine statische Klasse wird ausschließlich als Namespace verwendet - kein Problem. So werden statische Methoden verwendet. Wenn Sie diese Art des Aufrufs von Methoden stört, versuchen Sie, Erweiterungsmethoden oder die
using static
Deklaration zu verwenden.Die statische Klassenkennung ist grundsätzlich bedeutungslos - Problem . Es ist bedeutungslos, weil Entwickler nicht verwandte Methoden einfügen. Fügen Sie nicht verwandte Methoden in ihre eigenen statischen Klassen ein und geben Sie ihnen spezifische und verständliche Namen.
Wenn ein neues GLUM hinzugefügt wird, wird entweder (a) diese "Taschen" -Klasse berührt (SRP-Traurigkeit) - kein Problem, wenn Sie der Idee folgen, dass nur logisch verwandte Methoden in einer statischen Klasse sein sollten.
SRP
wird hier nicht verletzt, da das Prinzip für Klassen oder Methoden angewendet werden sollte. Einzelverantwortung für statische Klassen bedeutet, unterschiedliche Methoden für eine allgemeine "Idee" zu enthalten. Diese Idee kann ein Feature oder eine Konvertierung oder Iterationen (LINQ) oder eine Datennormalisierung oder -validierung sein ...oder seltener (b) eine neue "Taschen" -Klasse wird erstellt (mehr Taschen) - kein Problem. Klassen / statische Klassen / Funktionen - sind unsere (Entwickler-) Tools, die wir zum Entwerfen von Software verwenden. Hat Ihr Team einige Grenzen für die Verwendung von Klassen? Was sind die Höchstgrenzen für "mehr Taschen"? Bei der Programmierung dreht sich alles um den Kontext. Wenn Sie zur Lösung in Ihrem speziellen Kontext 200 statische Klassen haben, die verständlicherweise benannt und logisch in Namespaces / Ordnern mit logischer Hierarchie abgelegt sind, ist dies kein Problem.
Die Meta-Benennung ist unausweichlich schrecklich, nicht standardisiert und normalerweise intern inkonsistent, egal ob es sich um Helfer, Dienstprogramme oder was auch immer handelt - Problem. Geben Sie bessere Namen an, die das erwartete Verhalten beschreiben. Behalten Sie nur verwandte Methoden in einer Klasse, die Ihnen bei der besseren Benennung helfen.
quelle
A
mit 100 statischen Klassen mit einer Methode (in 100 Dateien) zu haben als eine statische KlasseA
mit 100 Methoden in einer einzelnen Datei.Math
statische Klasse aufruft .Nehmen Sie einfach die Konvention an, dass statische Klassen in solchen Situationen in C # wie Namespaces verwendet werden. Namespaces erhalten gute Namen, sollten diese Klassen auch. Die
using static
Funktion von C # 6 erleichtert auch das Leben ein wenig.Stinkende Klassennamen wie
Helpers
signalisieren, dass die Methoden nach Möglichkeit in besser benannte statische Klassen aufgeteilt werden sollten. Eine Ihrer hervorgehobenen Annahmen ist jedoch, dass die Methoden, mit denen Sie sich befassen, "paarweise nicht verwandt" sind, was eine Aufteilung auf bedeutet eine neue statische Klasse pro vorhandener Methode. Das ist wahrscheinlich in Ordnung, wennAls erfundenes Beispiel
Helpers.LoadImage
könnte so etwas werdenFileSystemInteractions.LoadImage
.Trotzdem könnte es zu statischen Klassenmethodenbeuteln kommen. Einige Möglichkeiten, wie dies passieren kann:
Es ist wichtig, sich daran zu erinnern, dass diese statischen Klassenmethodenbeutel in echten C # -Codebasen keine Seltenheit sind. Es ist wahrscheinlich nicht pathologisch, ein paar kleine zu haben .
Wenn Sie wirklich einen Vorteil darin sehen, dass jede "freie Funktion" -ähnliche Methode in einer eigenen Datei enthalten ist (was in Ordnung und sinnvoll ist, wenn Sie ehrlich beurteilen, dass dies tatsächlich der Wartbarkeit Ihres Projekts zugute kommt), können Sie eine solche statische Klasse anstelle einer statischen Klasse erstellen Teilklasse, wobei der statische Klassenname ähnlich wie bei einem Namespace verwendet und dann über verwendet wird
using static
. Beispielsweise:Program.cs
Foo / Bar.cs
Foo / Baz.cs
Flob / Wibble.cs
Flob / Wobble.cs
quelle
Im Allgemeinen sollten Sie keine "allgemeinen Dienstprogrammmethoden" haben oder benötigen. In Ihrer Geschäftslogik. Schauen Sie noch einmal genau hin und platzieren Sie sie an einem geeigneten Ort.
Wenn Sie eine Mathematikbibliothek oder etwas anderes schreiben, würde ich Erweiterungsmethoden vorschlagen, obwohl ich sie normalerweise hasse.
Sie können Erweiterungsmethoden verwenden, um Funktionen zu Standarddatentypen hinzuzufügen.
Nehmen wir zum Beispiel an, ich habe eine allgemeine Funktion MySort () anstelle von Helpers.MySort oder füge eine neue ListOfMyThings.MySort hinzu. Ich kann sie IEnumerable hinzufügen
quelle