Sollte eine Utility-Klasse statisch sein? [geschlossen]

76

Wenn ich eine Utility-Klasse entwerfen muss (z. B. ByteUtils oder StreamUtils oder StringUtils), welche ist die beste Entwurfsoption für sie?

  • Sollten es statische Klassen sein (da ich keine Zustände zum Speichern habe)
  • Sollten sie nicht statische Klassen sein (wenn die Objekte nicht verwendet werden, werden sie gc'd)

PS: Mit statischer Klasse meinte ich eine Klasse mit statischen Methoden (und nicht die innere statische Klasse).

Bitte geben Sie Ratschläge zur Auswahl des Designs.

nibin012
quelle
5
Sie müssen diese Frage umformulieren. Klassen der äußeren Ebene können in Java nicht statisch sein. Sie können nur statische Methoden haben. Nicht dasselbe.
Marquis von Lorne
Ja. Du hast Recht. Ich meinte eine Klasse mit statischen Methoden
nibin012
Während Ihre Beispiele (Byte, String, Stream) ziemlich klein sein sollten, wird das Testen dieses EJB ziemlich schwierig, wenn Sie zufällig einen 1k-LOC in EJB haben, der ein Mapper-Dienstprogramm mit statischen Methoden verwendet.
LAFK sagt Reinstate Monica

Antworten:

46

Wenn es sich um ein Allzweckdienstprogramm handelt, ist statisch IMO besser. Sie haben angegeben, dass Sie keine zu speichernden Status haben werden, daher verstehe ich nicht, warum Sie sie nicht statisch machen sollten. Wenn Sie es als statisch deklarieren, wird auch Speicherplatz gespart.

Gapton
quelle
10
Ein Schraubenzieher ändert sich nicht, er macht immer das Gleiche. Wenn dies auch für Ihre Utility-Klasse gilt, machen Sie sie auf jeden Fall statisch.
Gapton
10
Dies gilt für alle Methoden, die nicht vom Status des Objekts abhängen. Nicht nur Utility-Klassenmethoden.
Dorus
71

Meine Utility-Klassen sehen folgendermaßen aus:

// final, because it's not supposed to be subclassed
public final class FooUtil {

    // private constructor to avoid unnecessary instantiation of the class
    private FooUtil() {
    }

    public static int doSomethingUseful() {
    }

    // ...
}

Beachten Sie, dass die Dienstprogrammmethoden zwar leicht testbar und von außen leicht zugänglich sind, die Klassen, die sie verwenden, jedoch auch schwer zu testen sind, da es nicht einfach ist, diese Dienstprogrammmethoden zu verspotten. Zu viele solcher Dienstprogrammklassen können ein Zeichen für einen Mangel an OO-Design (prozedurale Programmierung) sein und den Code wirklich schwer testen.

Wenn Sie ein Abhängigkeitsinjektionsframework (Spring, Guice, was auch immer) verwenden, ist es möglicherweise eine gute Idee, die Utility-Klasse mit nicht statischen Methoden instanziierbar zu machen und sie zu einem injizierbaren Singleton zu machen. Auf diese Weise können Klassen, die diese Dienstprogrammmethoden verwenden, getestet werden, indem das Dienstprogrammobjekt verspottet wird.

JB Nizet
quelle
2
Wir können statische Methoden mit powermock code.google.com/p/powermock
nibin012
13
@ nibin012 Nur weil du kannst, heißt das nicht, dass du es solltest. In meinem Projekt ist PowerMock ein Werkzeug der ständigen Trauer - es ist schlecht mit anderen Werkzeugen, da es zu viel mit Klassenladern zu tun hat.
LAFK sagt Reinstate Monica
@ jb-nizet Könnten Sie bitte ein minimales Beispiel für Folgendes angeben:> Es ist möglicherweise eine gute Idee, die Utility-Klasse mit nicht statischen Methoden instanziierbar zu machen und sie zu einem injizierbaren Singleton zu machen. Es ist SGTM, aber ich habe Mühe, es umzusetzen.
Alexsalo
1
"Wenn Sie ein Abhängigkeitsinjektionsframework verwenden" - und wenn nicht, ist es eine schlechte Idee?
Linie
Sie sind keine Unit-Tests, nur weil Sie Powermocks verwenden. Im Allgemeinen ist die Verwendung eines Mock wie Powermock zum Testen einer von Ihnen entworfenen statischen Methode wahrscheinlich in irgendeiner Weise falsch, da Sie "zustandslose" Methoden überschreiben.
Wisienkas
24

Nur weil etwas statisch sein kann, heißt das nicht, dass es statisch sein sollte.

Es gibt noch eine andere Überlegung: Spott. Es ist schwieriger, statische Methoden in Ihren Tests zu verspotten, als das Verhalten einer Instanz einer Klasse zu verspotten.

Die Rede von unnötigen Heap-Zuordnungen und GCing von Objekten riecht für mich nach vorzeitiger Optimierung. Die JVM wird ziemlich gute Arbeit leisten, um diese Art von Problem zu beseitigen.

mrbaboo
quelle
9

Der einfachste Weg, eine Utility-Klasse zu definieren, ist eine Aufzählung ohne Instanzen

public enum Utility {;
     public static int utilityMethod(int x) { /* ... */ }
}

Eine Utility-Klasse sollte keinen oder nur einen minimalen Status haben, sodass Sie sich keine Gedanken über GCs machen sollten.

Sie können andere zustandsbehaftete Klassen für bestimmte Zwecke wie Builder oder Factory verwenden. Sie können das Objekt wie gewünscht erstellen und es verwerfen, wenn Sie fertig sind.

Peter Lawrey
quelle
1
Ich nehme an, Sie meinen keine statisch verschachtelte Klasse. Auf diese Weise müssen Sie nicht daran denken, den privaten Konstruktor zu erstellen, um zu verhindern, dass versehentlich eine Instanz der Utility-Klasse erstellt wird. Aufzählungen sind finalstandardmäßig.
Peter Lawrey
1
In Java enumkönnen veränderbare Felder vorhanden sein, Schnittstellen und abstrakte Methoden implementieren, sodass sie viel mehr als nur Konstanten sind. ;)
Peter Lawrey
3
@PeterLawrey, obwohl dies wahr ist, riecht es für mich nach Überentwicklung. Seit 1996 kann ich insgesamt null Mal zählen, dass jemand versehentlich eine Klasse instanziiert hat, die als einfaches statisches Dienstprogramm gedacht ist. Solche Schutzmaßnahmen bereitzustellen ist dumm, IMO, denn die Konsequenzen einer solchen Instanziierung sind, dass Sie sofort bemerken, dass es nicht funktioniert. Das Einfügen enumin die Mischung ändert jedoch, wie der müde Ingenieur um 3 Uhr morgens auf Koffein hüpft, das Ding liest und ihn für einen Moment fragen lässt, was los ist. Es ist einfach keine übliche Redewendung. Nutze classund sei glücklich.
4
Der primäre Punkt , den ich wirklich hier machen , ist , dass , wenn Sie eine verwenden enum, können Sie für den Leser sind telegraphing dass es einen Grund für die Zählung in seinem Design versteckt ist. Das gibt es nicht. Sie versuchen nur, es einfacher zu machen, als einen finalprivaten Konstruktor einzubauen, von denen keines IMO ein Problem darstellt. Das ist eine ungewöhnliche Redewendung. Und Sie haben jemanden gesehen, der versucht hat, eine Klasse statischer Dienstprogrammmethoden zu instanziieren? Ist das wichtig? Wenn jemand sieht, dass die Klasse die Methoden liefert, die er benötigt, weiß er, was er ist ---- warum sollte er sie instanziieren? Und was passiert, wenn sie es taten? Nicht viel.
3
Ich denke, wir müssen schon seit einiger Zeit einige unserer überbeschützenden Überlegungen in Frage stellen. Das Ausflippen von Gotos, das Vermeiden von Mehrfachretouren, der Instanziierungsschutz usw. usw. haben wirklich nur sehr begrenzte Vorteile. Was jedoch geschützt werden sollte, ist die Lesbarkeit des Codes. Versuchen Sie immer, so nah wie möglich an der Kategorie zu bleiben.
4

Es ist gut, die Klasse mit einem privaten Konstruktor als nicht statisch zu machen:

  • Wenn wir die Klasse statisch machen, wird die Klasse geladen, wenn die Anwendung bereitgestellt wird. Wenn sie nicht statisch ist, wird die Klasse geladen, wenn eine ihrer statischen Methoden aufgerufen wird
  • Durch das Erstellen eines privaten Konstruktors wird die Instanziierung der Klasse vermieden
Venkat
quelle
Wie benutzt man dann diese Klasse? NonStatic mit privatem Bau
Yousha Aleayoub
3

Normalerweise enthalten Dienstprogrammklassen statische Methoden und keine Attribute. Dieser Ansatz erleichtert die Verwendung ihrer Methoden, ohne die Klasse zu instanziieren. Hoffe das hilft.

Egor
quelle
2

Wenn Sie sie statisch machen können, dann tun Sie dies auf jeden Fall!

Mit anderen Worten, wenn sie keinen Status haben, sollten sie statisch sein.

Petar Ivanov
quelle
1
Ich habe in Projekten codiert, die diesem Prinzip folgten. "Wenn du kannst", das ist. Das Testen war dank dessen ein Albtraum. Und PowerMock machte die Sache noch schlimmer, da die Magie des Klassenladers mit anderen Tools auf nie leicht zu ermittelnde Weise kollidierte. Abgestimmt.
LAFK sagt Reinstate Monica
1
@LIttleAncientForestKami, ich stimme im Allgemeinen dem "wenn du kannst" zu. Ich denke jedoch, dass Petar sagte: "Wenn es keinen Grund gibt, etwas anderes als statisch zu verwenden, dann verwenden Sie statisch" (oder weniger ungeschickte Worte in diesem Sinne). Zumindest ist das die Bedeutung, die ich seiner Aussage entnommen habe. IOW: "Wenn Sie keine Instanz benötigen , erstellen Sie keine Instanz, nur um eine zu haben." Wieder meine Meinung zu seiner Aussage.
@tgm, genau. Vielen Dank!
Petar Ivanov
2

Nun, wenn Sie keinen Status zum Speichern haben, gibt es nichts zu GC, also würde ich mit statisch gehen, auf diese Weise vermeiden Sie unnötige Heap-Zuweisungen und GC.

user439407
quelle
2

Reine Dienstprogrammklassen sollten normalerweise statisch sein. Wenn Sie eine Klasse mit genau definierter Eingabe und Ausgabe, ohne Nebenwirkungen und ohne Status haben, sollte es per Definition eine statische Klasse sein.

Fügen Sie im Allgemeinen keine Komplexität hinzu (in diesem Fall Abhängigkeitsinjektion), bevor dies erforderlich ist, und dies hat einen Vorteil.

user1338062
quelle
1

Niemand erwähnt hier, dass statische Dienstprogrammmethoden nicht erweiterbar sind. Sie können sie nicht überschreiben. Sie können OOP nicht nutzen (insbesondere Polymorphysmus, das mächtigste Merkmal von OOP). Das führt zu einer Codeduplizierung.

PS Ich fand diesen Artikel sehr hilfreich. http://www.yegor256.com/2014/05/05/oop-alternative-to-utility-classes.html

Murat Mustafin
quelle
Definieren Sie "erweiterbar" ... nichts hindert Sie daran, Überladungen in Ihren eigenen Werkzeugklassen vorzunehmen, die die vorhandenen Werkzeuge aufrufen (kein großer Unterschied zum Unterklassen / Überladen von IMO). Wenn Sie die Duplizierung von Code verhindern möchten, können Sie immer Generika verwenden Damit Ihre Werkzeugfunktion eine größere Auswahl an Typen verarbeiten kann.
Nyerguds
Dieser Artikel scheint sich für eine "Verwenden von Objekten, um OOP zu sein" -Mentalität zu entscheiden, bei der es sich bei IMO nur um Speicherverschmutzung handelt . Dies gibt dem GC nicht nur zusätzliche Arbeit, sondern da Objektreferenzen gespeichert werden können, besteht bei jeder Objekterstellung das Risiko, dass Speicherlecks entstehen. Ist es nicht wert.
Nyerguds
Ich bin mir nicht sicher, warum dies abgelehnt wird. Ein guter Artikel, der zusammenfasst, warum dies die bessere Option ist: vojtechruzicka.com/avoid-utility-classes
Pratik
@Nyerguds Sie sind absolut falsch in Bezug auf zusätzliche Arbeit für den GC. Der übliche Weg, dies zu tun, besteht darin, einen Singleton (eine statische getInstance () -Methode) mit einem privaten Konstruktor zu haben.
Pratik
@Pratik Dann ist es Speicherverschmutzung, da es diese Objekte auf unbestimmte Zeit hält.
Nyerguds