Sollte ich statische Klassen für Methoden verwenden, die allgemeine Aufgaben ausführen und in meiner Anwendung aufgerufen werden?

8

Ich habe die letzten Stunden damit verbracht, mich über die Verwendung von staticKlassen zu informieren und herauszufinden, ob ich sie verwenden sollte oder nicht, bin aber immer noch zu keinem Ergebnis gekommen. Es scheint, dass das Argument in beide Richtungen gehen könnte. In meiner Anwendung habe ich sogenannte "Hilfsklassen" erstellt, die Methoden enthalten, die sehr häufige Aufgaben für mich erledigen und in meiner Anwendung aufgerufen werden ( ASP.Net MVCWeb App using C#). Die einfache Frage ist, ob sie wirklich statisch sind oder nicht ?

Hier ist ein Beispiel von einem meiner Helfer.

public static class ActiveDirectoryHelper
{
    public static PrincipalContext GetPrincipalContext(string ouName)
    {
        var fullOUName = string.Concat("OU=", ouName,",DC=");

        return new PrincipalContext(ContextType.Domain, "", fullOUName, ConfigurationManager.AppSettings["ServiceAccountUser"], ConfigurationManager.AppSettings["ServiceAccountPassword"]);
    }

    public static PrincipalSearcher GetAllUsersInOU(string ouName)
    {
        var principalContext = GetPrincipalContext(ouName);
        var userPrincipal = new UserPrincipal(principalContext);
        return new PrincipalSearcher(userPrincipal);
    }

    public static UserPrincipal GetUserPrincipal(string userName, string ouName)
    {
        var principalContext = GetPrincipalContext(ouName);
        return UserPrincipal.FindByIdentity(principalContext, userName);
    }
}
Matthew Verstraete
quelle
Es gibt kein Mandat zur Vermeidung statischer Klassen. Verwenden Sie sie, wenn dies sinnvoll ist. Es gibt gute Gründe, warum die Sprachdesigner sie aufgenommen haben.
Robert Harvey
5
Warum haben Sie diese Methoden nicht als statische Methoden in die zugehörigen Klassen aufgenommen, anstatt sie alle in eine Hilfsklasse zu setzen? Ihre erste Methode könnte beispielsweise eine statische Methode in der PrincipalContextKlasse sein und wie folgt aufgerufen werden : PrincipalContext.Get(ouName). Es ist im Wesentlichen eine Factory-Methode.
Robert Harvey
@ RobertHarvey Ich glaube nicht, dass ich folge. Diese Klasse befindet sich in meiner BLL und wird von vielen anderen Klassen (Controllern) auf der WebUI sowie von einer C # -Konsolen-App aufgerufen, die die nächtliche Wartung durchführt und um zu vermeiden, dass sie ständig neu codiert werden muss, während ich sie gerade in eine Hilfsklasse geschrieben habe.
Matthew Verstraete
5
Softwareentwicklung ist immer eine Reihe von Kompromissen. Welche Technik Sie verwenden, hängt davon ab, welche Kompromisse Sie anwenden möchten.
Robert Harvey
4
@ RobertHarvey: PrincipalContext und UserPrincipal sind Bibliotheksklassen,
Kevin Cline

Antworten:

3

Ich denke, statische Klassen sind in vielen Fällen nett. Ich könnte einfach sagen "benutze sie, wenn es nützlich ist", aber das ist nicht sehr hilfreich.

Meine Faustregel lautet (wie immer): Verstecke ich Abhängigkeiten? Wenn Sie der Meinung sind, dass eine "Helferklasse" nützlich ist (obwohl Sie auf einen geringen Zusammenhalt achten), fahren Sie auf jeden Fall fort. Stellen Sie nur sicher, dass Ihre Methoden nicht auf den globalen Status zugreifen. Reine statische Methoden sind sehr schön. Statische Methoden, die von einigen globalen Methoden abhängen oder DB-Verbindungen öffnen oder von der Festplatte / einer Konfigurationsdatei lesen, sind Zeitbomben.

Sie machen das Testen der Anwendung sehr schwierig (die einzige Möglichkeit, dies zu tun, besteht darin, das gesamte System manuell auszuführen, oder bei spröden automatischen Tests des gesamten Systems erhalten Sie keine Granularität). Sie machen es auch unmöglich, Implementierungen auszutauschen.

Denken Sie nur an das Abhängigkeitsinversionsprinzip und das Open / Closed-Prinzip! Stellen Sie sicher, dass Ihre Klassen steckbar sind. Stellen Sie sicher, dass sie nichts aus der Luft ziehen. Wenn Sie das tun, machen Sie so viele statische Methoden, wie Sie wollen!

Sara
quelle
2

Anscheinend verbergen Sie mit dieser statischen Klasse eine externe Abhängigkeit von Active Directory. Ein Problem hierbei ist, dass Sie keine statischen Aufrufe vortäuschen können, wenn Sie versuchen, die Klasse, die diese Methoden aufruft, einem Komponententest zu unterziehen. So verhindern Sie sofort die Testbarkeit Ihres Codes. Ich würde dies in eine Schnittstelle umgestalten, so etwas wie IProvideActiveDirectoryInformation und die konkrete Klasse ActiveDirectoryInformationProvider. Übergeben Sie dann die Schnittstelle im Konstruktor Ihres Controllers. Auf diese Weise können Sie die Betonklasse mit einem DI-Container verkabeln. Außerdem können Sie den ActiveDirectoryInformationProvider fälschen und für die Schnittstellenmethoden alles zurückgeben, was Sie möchten.

Ich würde auch versuchen, Dinge wie das PrincipalSearcher-Objekt in der Benutzeroberfläche nicht zurückzugeben. Wenn Ihre Methode GetAllUsersInOU () ist, würde ich eine Liste von Benutzern oder Benutzernamen erwarten.

Fran
quelle
Sie sind sich nicht sicher, was Sie unter "Ausblenden einer externen Abhängigkeit von Active Directory" verstehen. Ich lese aus AD und diese Klasse wurde erstellt, um die Codierung zu reduzieren, die zum Herstellen von Verbindungen und zum Abrufen von Basisdaten erforderlich ist.
Matthew Verstraete
das ist, was ich meine. Eine ausführlichere Erklärung finden Sie in Kai's Antwort. Was Sie jedoch nicht tun, ist, Ihren Code von allen Abhängigkeiten des Codes abhängig zu machen, den Sie aufrufen.
Fran
1

Eine Klasse sollte statisch sein, wenn sie in Ihrer Anwendung nur als abstraktes Konzept vorhanden ist.

Angenommen, Sie erstellen einen Klon von Twitter. Sie können zwei Arten von Tweets, Benutzer-Tweets und Anzeigen haben. Beide haben ein gemeinsames Verhalten, sind aber unterschiedlich. Sie möchten also Polymorphismus und eine Fabrik verwenden, um das eine oder andere zu erstellen.

Diese 2 Tweets-Klassen sollten konkrete Klassen sein, da es sich um reale Einheiten handelt. Ihre Domain wird durch diese Klassen definiert.

Die Factory sollte statisch sein, da sie nur auf abstrakter Ebene vorhanden ist, um Ihre Anwendung besser zu gestalten und Ihnen zu helfen, Code wiederzuverwenden, der eine Art Tweet erstellt. Ihre Domain wird von dieser Factory auf keiner Ebene definiert.

Wenn Sie also nicht der Meinung sind, dass eine Klasse jemals instanziiert werden sollte, aber nicht erweitert werden muss, um verwendet zu werden, ist dies wahrscheinlich ein gutes Zeichen dafür, dass sie statisch sein sollte.

Steve Chamaillard
quelle
Dies würde wirklich von der Art der Fabrik abhängen. Ein einfaches static A BuildA() { return new A(); }sicher, das ist in Ordnung. Wenn Sie jedoch etwas Komplexeres benötigen, z. B. wenn A Abhängigkeiten hat, die injiziert werden müssen, oder wenn verschiedene Teile Ihres Systems unterschiedliche Factory-Instanzen benötigen (abstraktes Factory-Muster), wird dies durch eine statische Methode nicht abgeschnitten.
Sara
Vielen Dank für Ihren Kommentar. Es hört sich nicht so an, als wäre die Fabrik, von der Sie sprechen, am Ende so abstrakt, dass es sich um ein konkretes Konzept handelt, das instanziiert werden muss (insbesondere, weil Sie sagten, Sie brauchten mehrere verschiedene Fabriken). Andererseits ist sowieso nichts in Stein gemeißelt und es können nur Ratschläge zu diesem Thema gegeben werden.
Steve Chamaillard
1
Es gibt viele Entitäten, bei denen es sich um "Pure Fabrication" handelt, die in keiner Weise oder Form in die Domäne übersetzt werden, z. B. UserDao. Dies ist jedoch kein Hinweis darauf, ob es statisch sein sollte oder nicht. Es sollte statisch sein, wenn die Arbeitseinheiten, die es ausführt, nicht voneinander abhängen und erweiterbar sein sollten, z. B. Mathematikunterricht.
Chris Wohlert
@ChrisWohlert sehr interessanter Kommentar (hochgedreht), aber hängt es nicht nur vom Kontext ab? Ich denke, eine App über Mathematik möchte, dass eine Mathematikklasse eine der Kernklassen ist und instanziierbar ist. Ist UserDao eine Art Repository zwischen Benutzer und DB-Schicht? Wenn ja, warum sollten Sie es jemals instanziieren wollen? Sie könnten es trotzdem injizieren, obwohl Sie niemals ein Objekt dafür erstellen würden, da es nicht "existiert". Was denken Sie?
Steve Chamaillard
1
@SteveChamaillard Sie gehen davon aus, dass es sinnvoll ist, nur "echte" Objekte zu instanziieren. Es erinnert mich an diese OOP 101-Analogien, in denen Sie die abstrakte Klasse "Fruit" und "Apple" geerbt haben - wobei OOP-Objekte Objekte der realen Welt darstellen. Aber Sie müssen sich nicht so einschränken. OOP ist ein Werkzeug, also benutzen die Leute Objekte für "reine Erfindungen", auch das erleichtert ihnen das Leben und ich sehe nichts falsches daran ...
qbd
1

Eines der Dinge, die in der objektorientierten Programmierung vorgeschlagen werden, ist schlecht (der Titel soll Ihre Aufmerksamkeit erregen, und der Inhalt ist umstritten, aber unterhaltsam) *Handler, *Managerund *DoerKlassen sind im Allgemeinen ein Codegeruch, der darauf hinweist, dass jemand versucht, die Objektorientierung auf eine zu erzwingen Problem, das für eine prozedurale Implementierung besser geeignet ist.

In C # können Sie statische Klassen als Modul-Namespaces für Prozeduren verwenden und diese vorzugsweise als solche benennen. Ich denke, so geht das, aber nicht in Ihrem speziellen Fall.

Anwendungen Ihrer speziellen Implementierung weisen Verhaltensabhängigkeiten des globalen Status auf (z. B. die Berechtigungen eines bestimmten Benutzers) und sollten daher eine injizierte Abhängigkeit sein, damit der Code, der diese verwendet, isoliert einem Komponententest unterzogen werden kann.

Robert Jørgensgaard Engdahl
quelle
0

Ich vermisse vielleicht etwas, aber meiner Meinung nach läuft die Antwort auf die Methoden und Mitgliedsvariablen hinaus.

Wenn diese alle statisch sind, kann (und sollte) die Klasse selbst statisch gemacht werden. Wenn nicht, ist es keine statische Klasse.

Hinweis: Es gibt nichts, was die Klasse dazu zwingt , statisch zu sein, selbst wenn die Methoden und Variablen alle statisch sind.

Robbie Dee
quelle
Dieselbe Klasse, die dieselben Dinge tut, kann sowohl statisch als auch nicht statisch gestaltet werden. Es muss immer eine Designauswahl getroffen werden.
Sara
Es kann eine Entwurfsauswahl geben, aber die Implementierung ist etwas willkürlich. Nichts zwingt Sie dazu, die Methode oder Klasse statisch zu kennzeichnen - selbst wenn keine Instanzvariable vorhanden ist, obwohl einige Tools wie ReSharper dies aufgreifen ...
Robbie Dee
Aber wann sollte ich alle Methoden / Mitglieder statisch machen oder nicht? Das ist hier die Frage. Wann statisch zu verwenden ist und wann nicht.
Matthew Verstraete
Wenn keine der Mitgliedsvariablen oder -methoden auf einer Instanz der Klasse beruht, haben Sie selbst eine echte statische Klasse. Dies sind von Natur aus Dinge wie Hilfsklassen oder Dienstprogramme und dergleichen.
Robbie Dee
0

Betrachten Sie die Programmiersprache, die Sie verwenden (C #), als eine Reihe von Werkzeugen.

Es gibt kein Regelwerk, kein "sollte" oder "sollte nicht".

Schauen Sie sich den Job an und wählen Sie das beste Werkzeug für den Job.

Wenn Sie eine global verfügbare Sammlung von Methoden benötigen, die für alle Threads gleich ist, sind statische Klassen ein gutes Werkzeug. Wenn Sie Daten innerhalb der Klasse speichern möchten (für jeden Thread unterschiedlich), sind dies wahrscheinlich nicht der Fall.


quelle
0

In Ihrer Helferklasse ist nichts falsch. Ich muss zugeben, dass ich diese Art von Utils , Helfern oder Inhabern verwende , um bestimmte Ressourcen / Logik von verschiedenen Orten aus zugänglich zu machen.

Ein Architekt meiner Firma sagt mir jedoch immer wieder, dass diese Klassen häufig Code sammeln, bei dem ich nicht weiß, wo ich ihn platzieren soll. Er mag es auch nicht, weil Sie Komponenten aus Ebenen mitbringen könnten, auf die die oberen / unteren Ebenen keinen Zugriff haben sollten, und sie Aufgaben außerhalb ihrer Verantwortlichkeiten ausführen. Es bringt auch einige Probleme zur Testzeit.

Es macht mir nichts aus. Ich benutze sie und ich benutze sie so richtig, wie ich denke, dass es benutzt werden sollte. Und es funktioniert gut. Also mach dir keine Sorgen.

Es ist wahr, dass es Ihnen zum Zeitpunkt des Unit-Tests schwer fallen wird, sich darüber lustig zu machen. Aber es wird etwas länger dauern. Es gibt Bibliotheken, die dieses Problem behandeln.

Ein anderer Ansatz könnte Sie von solchen Mängeln (beim Testen) abhalten. Zum Beispiel Singleton-Muster. Injizieren der Instanz als Komponentenabhängigkeit und Umwandeln von Methoden in Instanzmethoden.

Soweit ich weiß, sehen Ihre Lösungen für mich jedenfalls gut aus.

Laiv
quelle