web-dev-qa-db-de.com

Gebrauchsklassen sind böse?

Ich habe diesen Thread gesehen 

Wenn eine "Utilities" -Klasse böse ist, wo gebe ich meinen generischen Code ein?

und dachte, warum sind Nutzerklassen böse? 

Nehmen wir an, ich habe ein Domänenmodell, das Dutzende von Klassen tief ist. Ich muss xml-ify-Instanzen können. Mache ich eine toXml-Methode für das übergeordnete Element? Mache ich eine MyDomainXmlUtility.toXml-Helper-Klasse? Dies ist ein Fall, in dem die geschäftlichen Anforderungen das gesamte Domänenmodell abdecken. Gehört es wirklich als Instanzmethode? Was ist, wenn es eine Reihe von Hilfsmethoden für die XML-Funktionalität der Anwendung gibt?

77
hvgotcodes

Nutzungsklassen sind nicht gerade böse, aber sie können gegen die Prinzipien verstoßen, die ein gutes objektorientiertes Design ausmachen. In einem objektorientierten Design sollten die meisten Klassen ein einziges Element und alle seine Attribute und Operationen darstellen. Wenn Sie mit einer Sache arbeiten, sollte diese Methode wahrscheinlich ein Mitglied dieser Sache sein.

Es gibt jedoch Zeiten, in denen Sie mithilfe von Dienstprogrammklassen eine Reihe von Methoden zusammenfassen können. Ein Beispiel ist die Klasse Java.util.Collections, die eine Reihe von Dienstprogrammen bereitstellt, die in jeder Java Collection verwendet werden können. Diese sind nicht spezifisch für einen bestimmten Collection-Typ, sondern implementieren Algorithmen, die für jede Collection verwendet werden können.

In Wirklichkeit müssen Sie über Ihr Design nachdenken und feststellen, wo es am sinnvollsten ist, die Methoden zu verwenden. Normalerweise handelt es sich dabei um Operationen innerhalb einer Klasse. In manchen Fällen handelt es sich jedoch tatsächlich um eine Dienstprogrammklasse. Wenn Sie jedoch eine Dienstprogrammklasse verwenden, werfen Sie nicht einfach zufällige Methoden hinein, sondern organisieren Sie die Methoden nach Zweck und Funktionalität.

105
Thomas Owens

Ich denke, dass der allgemeine Konsens darin besteht, dass Gebrauchsklassen nicht böse sind per se. Sie müssen sie nur mit Bedacht einsetzen:

  • Entwerfen Sie die statischen Dienstprogrammmethoden so, dass sie allgemein und wiederverwendbar sind. Stellen Sie sicher, dass sie staatenlos sind. keine statischen Variablen.

  • Wenn Sie über viele Dienstprogrammmethoden verfügen, unterteilen Sie diese in Klassen, damit Entwickler sie leichter finden können.

  • Verwenden Sie keine Dienstprogrammklassen, bei denen statische Methoden oder Instanzmethoden in einer Domänenklasse eine bessere Lösung darstellen. Überlegen Sie sich beispielsweise, ob Methoden in einer abstrakten Basisklasse oder einer instanziierbaren Hilfsklasse eine bessere Lösung wären.

  • Ab Java 8 sind "Standardmethoden" in einer Schnittstelle möglicherweise eine bessere Option als Dienstprogrammklassen.


Die andere Möglichkeit, diese Frage zu betrachten, besteht darin, zu beobachten, dass in der zitierten Frage "Wenn Dienstprogrammklassen" böse "sind ein Strohmann-Argument ist. Es ist wie ich frage:

"Wenn Schweine fliegen können, sollte ich einen Regenschirm tragen?".

In der obigen Frage sage ich eigentlich nicht, dass Schweine fliegen können ... oder dass ich der These zustimme, dass sie könnten fliegen.

Typisch "xyz ist böse" Aussagen sind rhetorische Mittel, die einen zum Nachdenken anregen sollen, indem sie einen extremen Standpunkt vertreten. Sie sind selten (wenn überhaupt) als wörtliche Tatsachenerklärungen gedacht.

52
Stephen C

Dienstprogrammklassen sind problematisch, da sie die Verantwortlichkeiten nicht mit den Daten zusammenfassen, die sie unterstützen.

Sie sind jedoch äußerst nützlich und ich baue sie ständig als permanente Strukturen oder als Sprungbrett während eines gründlicheren Refaktors.

Aus einer Clean Code - Perspektive verstoßen die Utility-Klassen gegen die Einzelverantwortung und das Open-Closed-Prinzip. Sie haben viele Gründe zu ändern und sind nicht erweiterbar. Sie sollten eigentlich nur beim Refactoring als Zwischengrube existieren.

12
Alain O'Dea

Ich nehme an, es wird böse, wenn 

1) Es wird zu groß (gruppieren Sie sie in diesem Fall einfach in sinnvolle Kategorien).
2) Methoden, die keine statischen Methoden sein sollten, sind vorhanden  

Aber solange diese Bedingungen nicht erfüllt sind, sind sie meiner Meinung nach sehr nützlich.

7
Enno Shioji

Faustregel

Sie können dieses Problem aus zwei Perspektiven betrachten:

  • Allgemeine *Util-Methoden sind oft ein Hinweis auf schlechte Code-Design- oder Lazy-Namenskonvention. 
  • Dies ist eine legitime Designlösung für wiederverwendbare, domänenübergreifende Funktionen. Bitte beachten Sie, dass für fast alle gängigen Probleme bereits Lösungen vorhanden sind. 

Beispiel 1. Korrekte Verwendung von util Klassen/Modulen. Beispiel für eine externe Bibliothek

Nehmen wir an, Sie schreiben eine Anwendung, die Kredite und Kreditkarten verwaltet. Daten aus diesen Modulen werden über Webservices im json-Format bereitgestellt. In der Theorie können Sie Objekte manuell in Zeichenfolgen konvertieren, die sich in json befinden, dies würde jedoch das Rad neu erfinden. Eine korrekte Lösung wäre, in beide Module eine externe Bibliothek aufzunehmen, die zum Konvertieren von Java-Objekten in das gewünschte Format verwendet wird. (Im Beispiel habe ich gson gezeigt)

 enter image description here


Beispiel 2. Korrekte Verwendung von util Klassen/Modulen. Schreiben Sie Ihre eigene util ohne Entschuldigung an andere Teammitglieder

Als Anwendungsfall wird davon ausgegangen, dass wir einige Berechnungen in zwei Anwendungsmodulen durchführen müssen, aber beide müssen wissen, wann in Polen gesetzliche Feiertage gelten. Theoretisch können Sie diese Berechnungen innerhalb von Modulen durchführen, aber es ist besser, diese Funktionalität in ein separates Modul zu extrahieren. 

Hier ist ein kleines, aber wichtiges Detail. Die Klasse/das Modul, das Sie geschrieben haben, heißt nicht HolidayUtil, sondern PolishHolidayCalculator. Funktionell handelt es sich um eine util-Klasse, aber wir haben es geschafft, generisches Word zu vermeiden. 

 enter image description here

4
Marcin Szymczak

Ich stimme nicht völlig zu, dass Nutzerklassen böse sind.

Eine Utility-Klasse verstößt zwar in gewisser Weise gegen OO -Prinzipale, sie sind jedoch nicht immer schlecht.

Stellen Sie sich zum Beispiel vor, Sie möchten eine Funktion, die eine Zeichenfolge aller Teilzeichenfolgen löscht, die mit dem Wert x übereinstimmen.

stl c ++ unterstützt das jetzt nicht direkt.

Sie könnten eine polymorphe Erweiterung von std::string erstellen.

Aber das Problem ist, möchten Sie wirklich, dass JEDE Zeichenfolge, die Sie in Ihrem Projekt verwenden, Ihre erweiterte Zeichenfolgeklasse ist?

Es gibt Zeiten, in denen OO nicht wirklich sinnvoll ist, und dies ist einer von ihnen. Wir möchten, dass unser Programm mit anderen Programmen kompatibel ist. Daher bleiben wir bei std::string und erstellen eine Klasse StringUtil_ (oder etwas anderes).

Ich würde sagen, dass es am besten ist, wenn Sie pro Klasse einen Gebrauchswert beibehalten. Ich würde sagen, es ist dumm, für alle Klassen einen oder für eine Klasse viele Utensilien zu haben.

3
HumbleWebDev

Wenn ich jetzt auf diese Frage zurückblicke, würde ich sagen, dass C # -Erweiterungsmethoden die Notwendigkeit von Dienstklassen vollständig aufheben. Aber nicht alle Sprachen verfügen über ein derart geniales Konstrukt.

Sie haben auch JavaScript, mit dem Sie dem vorhandenen Objekt einfach eine neue Funktion hinzufügen können. 

Ich bin mir jedoch nicht sicher, ob es wirklich eine elegante Möglichkeit gibt, dieses Problem in einer älteren Sprache wie C++ zu lösen ...

Good OO - Code ist schwer zu schreiben und schwer zu finden, da Good OO viel mehr Zeit/Wissen erfordert als das Schreiben von anständigem Funktionscode.

Und wenn Sie über ein begrenztes Budget verfügen, ist Ihr Chef nicht immer glücklich darüber, dass Sie den ganzen Tag damit verbracht haben, eine Reihe von Kursen zu schreiben ...

3
HumbleWebDev

Utility-Klassen sind schlecht, weil sie bedeuten, dass Sie zu faul waren, einen besseren Namen für die Klasse zu finden :)

Davon abgesehen bin ich faul. Manchmal müssen Sie nur die Arbeit erledigen und Ihr Geist ist leer. Dann beginnen sich die "Utility" -Klassen einzuschleichen.

3
Larry Watanabe

Es ist sehr einfach, etwas als Dienstprogramm zu kennzeichnen, nur weil der Designer keinen geeigneten Ort für den Code finden konnte. Es gibt oft nur wenige echte "Dienstprogramme".

Als Faustregel gilt, dass ich normalerweise Code in dem Paket verwende, in dem er zuerst verwendet wird, und dann nur an einer allgemeineren Stelle umwandeln, wenn ich finde, dass er später wirklich woanders benötigt wird. Die einzige Ausnahme ist, wenn ich bereits ein Paket mit ähnlichen/verwandten Funktionen habe und der Code dort am besten passt.

2
mdma

Dienstprogrammklassen, die stateless statische Methoden enthalten, können nützlich sein. Diese Geräte sind oft sehr leicht zu testen.

2
seand

Die meisten Util-Klassen sind schlecht, weil:

  1. Sie erweitern den Umfang der Methoden. Sie machen Code öffentlich, der sonst privat wäre. Wenn die util-Methode von mehreren Aufrufern in separaten Klassen benötigt wird und stabil ist (d. H. Nicht aktualisiert werden muss), ist es meiner Meinung nach besser, private Hilfsmethoden in die aufrufende Klasse zu kopieren und einzufügen. Sobald Sie es als API verfügbar machen, wird es schwieriger zu verstehen, was der öffentliche Einstiegspunkt für eine jar-Komponente ist (Sie pflegen eine Struktur, die als Hierarchie mit einem übergeordneten Element pro Methode bezeichnet wird). Dies ist einfacher, mental in Komponenten zu trennen, was schwieriger ist Sie haben Methoden aus mehreren übergeordneten Methoden aufgerufen. 
  2. Sie führen zu einem toten Code. Util-Methoden werden im Laufe der Zeit ungenutzt, wenn sich Ihre App weiterentwickelt und am Ende ungenutzter Code verwendet, der Ihre Codebasis belastet. Wenn es privat geblieben wäre, würde Ihr Compiler Ihnen mitteilen, dass die Methode nicht verwendet wird, und Sie könnten sie einfach entfernen (der beste Code ist überhaupt kein Code). Wenn Sie eine solche Methode als nicht privat festgelegt haben, ist Ihr Computer nicht mehr in der Lage, nicht verwendeten Code zu entfernen. Es kann aus einer anderen JAR-Datei aufgerufen werden, wenn der Computer alles weiß.

Es gibt einige Analogien zu statischen und dynamischen Bibliotheken.

1

Mit Java 8 können Sie statische Methoden in Schnittstellen verwenden ... Problem gelöst.

1
Marc T

Gebrauchsklassen sind nicht immer böse. Sie sollten jedoch nur die Methoden enthalten, die für eine Vielzahl von Funktionen üblich sind. Wenn es Methoden gibt, die nur für eine begrenzte Anzahl von Klassen verwendet werden können, sollten Sie die Erstellung einer abstrakten Klasse als gemeinsames übergeordnetes Element in Betracht ziehen und die Methoden darin einfügen.

0
Sid J