Ich habe meine Gedanken zu statischen Klassen in einer früheren Stack Overflow-Antwort niedergeschrieben: Klasse mit einer einzigen Methode - bester Ansatz?
Früher liebte ich Utility-Klassen, die mit statischen Methoden gefüllt waren. Sie ermöglichten eine großartige Konsolidierung von Hilfsmethoden, die andernfalls herumliegen und Redundanz und Wartungsaufwand verursachen würden. Sie sind sehr einfach zu verwenden, keine Instanziierung, keine Entsorgung, einfach abfeuern und vergessen. Ich schätze, das war mein erster unwissentlicher Versuch, eine serviceorientierte Architektur zu schaffen - viele zustandslose Dienste, die einfach nur ihre Aufgabe erfüllen und sonst nichts. Wenn ein System jedoch wächst, werden Drachen kommen.
Polymorphismus
Angenommen, wir haben die Methode UtilityClass.SomeMethod, die fröhlich vor sich hin brummt. Plötzlich müssen wir die Funktionalität leicht ändern. Der größte Teil der Funktionalität ist derselbe, aber wir müssen trotzdem ein paar Teile ändern. Wenn es sich nicht um eine statische Methode handeln würde, könnten wir eine abgeleitete Klasse erstellen und den Inhalt der Methode nach Bedarf ändern. Da es sich um eine statische Methode handelt, können wir das nicht. Natürlich können wir eine neue Klasse erstellen und darin die alte Methode aufrufen, wenn wir nur eine Funktion vor oder nach der alten Methode hinzufügen wollen - aber das ist einfach nur grob.
Probleme mit der Schnittstelle
Statische Methoden können aus logischen Gründen nicht über Schnittstellen definiert werden. Und da wir statische Methoden nicht überschreiben können, sind statische Klassen nutzlos, wenn wir sie über ihre Schnittstelle weitergeben müssen. Dies macht es unmöglich, statische Klassen als Teil eines Strategiemusters zu verwenden. Wir könnten einige Probleme beheben, indem wir Übergabe von Delegierten anstelle von Schnittstellen .
Prüfung
Dies geht im Grunde Hand in Hand mit den oben erwähnten Schnittstellenproblemen. Da unsere Möglichkeiten, Implementierungen auszutauschen, sehr begrenzt sind, werden wir auch Probleme haben, den Produktionscode durch Testcode zu ersetzen. Auch hier können wir sie verpacken, aber das erfordert, dass wir große Teile unseres Codes ändern, nur um Wrapper anstelle der eigentlichen Objekte akzeptieren zu können.
Fosters Kleckse
Da statische Methoden in der Regel als Utility-Methoden verwendet werden und Utility-Methoden in der Regel verschiedene Zwecke haben, werden wir schnell mit einer großen Klasse enden, die mit nicht kohärenter Funktionalität gefüllt ist - idealerweise sollte jede Klasse einen einzigen Zweck innerhalb des Systems haben. Mir wäre eine fünffache Anzahl von Klassen viel lieber, solange ihre Zwecke gut definiert sind.
Kriechende Parameter
Zunächst einmal könnte diese kleine, niedliche und unschuldige statische Methode einen einzigen Parameter annehmen. Wenn die Funktionalität wächst, werden ein paar neue Parameter hinzugefügt. Bald kommen weitere Parameter hinzu, die optional sind, so dass wir Überladungen der Methode erstellen (oder einfach Standardwerte hinzufügen, in Sprachen, die dies unterstützen). Schon bald haben wir eine Methode, die 10 Parameter benötigt. Nur die ersten drei sind wirklich erforderlich, die Parameter 4-7 sind optional. Aber wenn Parameter 6 angegeben wird, müssen auch die Parameter 7-9 ausgefüllt werden... Hätten wir eine Klasse mit dem einzigen Zweck erstellt, das zu tun, was diese statische Methode tat, könnten wir dieses Problem lösen, indem wir die erforderlichen Parameter in den Konstruktor aufnehmen und dem Benutzer erlauben, optionale Werte über Eigenschaften oder Methoden zu setzen, um mehrere voneinander abhängige Werte gleichzeitig zu setzen. Wenn eine Methode eine derartige Komplexität erreicht hat, muss sie höchstwahrscheinlich ohnehin in einer eigenen Klasse untergebracht werden.
Aufforderung an die Verbraucher, ohne Grund eine Instanz von Klassen zu erstellen
Eines der häufigsten Argumente lautet: Warum verlangen wir, dass die Verbraucher unserer Klasse eine Instanz erzeugen, um diese eine Methode aufzurufen, während sie danach keine Verwendung mehr für diese Instanz haben? Die Erzeugung einer Instanz einer Klasse ist in den meisten Sprachen ein sehr billiger Vorgang, so dass die Geschwindigkeit keine Rolle spielt. Die Hinzufügung einer zusätzlichen Codezeile für den Verbraucher ist ein geringer Preis für die Schaffung der Grundlage für eine viel besser wartbare Lösung in der Zukunft. Und schließlich, wenn Sie die Erstellung von Instanzen vermeiden wollen, erstellen Sie einfach einen Singleton-Wrapper Ihrer Klasse, der eine einfache Wiederverwendung ermöglicht - allerdings setzt dies voraus, dass Ihre Klasse zustandslos ist. Wenn sie nicht zustandslos ist, können Sie immer noch statische Wrapper-Methoden erstellen, die alles handhaben und Ihnen auf lange Sicht alle Vorteile bieten. Schließlich können Sie auch eine Klasse erstellen, die die Instanziierung verbirgt, als ob sie ein Singleton wäre: MyWrapper.Instance ist eine Eigenschaft, die einfach zurückgibt new MyClass();
Nur ein Sith handelt in absoluten Zahlen
Natürlich gibt es Ausnahmen von meiner Abneigung gegenüber statischen Methoden. Echte Utility-Klassen, die kein Risiko der Aufblähung darstellen, sind hervorragende Fälle für statische Methoden - System.Convert als Beispiel. Wenn es sich bei Ihrem Projekt um ein einmaliges Projekt handelt, das nicht gewartet werden muss, ist die Gesamtarchitektur wirklich nicht sehr wichtig - statisch oder nicht statisch spielt keine Rolle - die Entwicklungsgeschwindigkeit hingegen schon.
Normen, Normen, Normen!
Die Verwendung von Instanzmethoden hindert Sie nicht daran, auch statische Methoden zu verwenden, und umgekehrt. Solange es eine Begründung für die Unterscheidung gibt und diese standardisiert ist. Es gibt nichts Schlimmeres, als eine Geschäftsschicht zu sehen, in der es von verschiedenen Implementierungsmethoden wimmelt.