Wann sollte ich statische Methoden und Variablen benutzen?

davidh38

Bekanntes Mitglied
Wenn ich nur ein Objekt von einer Klasse brauche, mache ich alles statisch. Ist das eine gute Methode oder sollte ich trotzdem eine Instanz kreiern und wenn ja warum?

Gibt es vielleicht einen "good practices"-Guide für solche Situationen?
 

tagedieb

Top Contributor
Das kommt auf deinen UseCase und Requirments darauf an.

Wenn du mit Spring und Dependency Injection arbeitest kannst du auf statische Zugriffe fast ausschliesslich verzichten und POJOs verwenden.

Wenn du aber eine zentrale Klasse benoetigst um allgemeine Methoden zu definieren kann auch static der richtige Weg sein. Als Beispiel schau dir mal java.lang.Math an.
 

davidh38

Bekanntes Mitglied
Das kommt auf deinen UseCase und Requirments darauf an.

Wenn du mit Spring und Dependency Injection arbeitest kannst du auf statische Zugriffe fast ausschliesslich verzichten und POJOs verwenden.

Wenn du aber eine zentrale Klasse benoetigst um allgemeine Methoden zu definieren kann auch static der richtige Weg sein. Als Beispiel schau dir mal java.lang.Math an.

Danke erstmal für deine Antwort. Wann sollte ich statische Klassen und wann sollte ich das Singletonpattern verwenden? Meine Klasse ist eine Formatterklasse, die Strings "zurechtschneidet".
 

faetzminator

Gesperrter Benutzer
Utility-Klassen (eben so wie Math) sind meist static. Auch in diesem Fall kann man die Methoden static machen (wie die StringUtils aus common-lang). Aber static zieht halt die bekannten Probleme nach sich... keine Vererbung!
 

r.w.

Bekanntes Mitglied
... Aber static zieht halt die bekannten Probleme nach sich... keine Vererbung!

Wer sagt das?

Java:
public class A {
   static Double parseString(String s) {
      return Double.parseDouble(s);
   }
}

public class B extends A {

}

public class Main {

    public static void main(String[] args) {
        Double dbl = B.parseString("3.59");
        System.out.println("dbl = " + dbl);
    }

}

;-)
 

Landei

Top Contributor
Da ist [c]parseString[/c] zwar sichtbar, wird aber nicht vererbt. Z.B. geht folgendes nicht, was bei einer nicht-statischen Methode funktionieren würde:

Java:
public class A {
   static Double parseString(String s) {
      return Double.parseDouble(s);
   }
}
 
public class B extends A {
   static Double parseString(String s) {
      return Math.round(super.parseString(s));
   }
}
 

faetzminator

Gesperrter Benutzer
Auf dieses Beispiel bezogen: natürlich ist in diesem Fall static einfach nur doof. Aber man beginnt immer klein. Zuerst wird wohl Klasse A vorhanden gewesen sein. Irgendwann musste man für Fall XY die modifizierte Version in B implementieren. Was macht man nun?
 

r.w.

Bekanntes Mitglied
Da ist [c]parseString[/c] zwar sichtbar, wird aber nicht vererbt. Z.B. geht folgendes nicht, was bei einer nicht-statischen Methode funktionieren würde:

Java:
//...
public class B extends A {
   static Double parseString(String s) {
      return Math.round(super.parseString(s));
   }
}

Mal abgesehen davon, ob es sinnvoll ist, statische Methoden zu überschreiben, da sich
dadurch ja die Funktionalität ändert, was eigentlich einen neuen Bezeichner nötig machen
würde...

Mag sein, aber mit super spricht man (genau wie mit this) doch nur Instanz-Methoden
und keine statischen Methoden an. So z.B. würde es wieder funktionieren:

Java:
public class B extends A {
   static Double parseString(String s) {
      return Math.round(A.parseString(s));
   }
}

Kann durchaus sein, dass ich komplett daneben liege, aber die Frage, die sich mir stellt ist:
Ist Vererbung abhängig davon, dass man die Methode über super ansprechen kann,
oder davon, dass die Methode auf die abgeleitete Klasse übertragen wird?
Was ja offensichtlich der Fall ist, da ich sie ja über "B." ansprechen kann.
 

faetzminator

Gesperrter Benutzer
Die "Utility"-Klasse wird halt überall im Code direkt mit [c]A. ...()[/c] angesprochen. Das kann ich nicht einfach mit einer Zeile Code ändern was anderes verwenden. Und Mocking für Testing ist ebenfalls eingeschränkt, hatte da letztens zwei, drei Beispiele, welche mir aber gerade leider nicht einfallen.
 

tagedieb

Top Contributor
Static unterstuetzt weder Vererbung noch kann eine Methode ueberschrieben werden. Im guenstigsten Fall kann sie hoechstens versteckt werden.

Nach Code Conventions sollte eine statische Methode IMMER via Klasse aufgerufen werden und nicht via Instanzvariable (Ausnahme: die statische Methode ist Teil derselben Klasse)

Ansonsten sollte eine statische Methode wie folgt aufgerufen werden:

Java:
    Double a = A.parseString(..);
    Double b = B.parseString(..);

Jetzt spielt es keine Rolle ob B von A erbt oder nicht....
So ist der Code eindeutig und verstaendlich, alles andere fuehrt unweigerlich zu Fehlern und langen debugging Sessions...



Meine Klasse ist eine Formatterklasse, die Strings "zurechtschneidet".

Fuer Formatterklassen gibt es bereits hunderte von Loesungen. Wenn du ein Framework verwendest wird da sicher schon Formatterklassen geben und man kann da auch seine Eigenen schreiben.

Ein Singleton macht hier aus meiner Sicht keinen Sinn. Ein Singleton braucht man nur wenn man sichersellen muss, das GENAU 1 Instanz einer Klasse existiert. Das duerfte auf einen Formatter nicht zutreffen. Eher das Gegenteil ist der Fall, das man mehrere Formatter mit unterschiedlichen Parameters verwendet. Beispiel: DateFormat
 

Marco13

Top Contributor
Wenn ich nur ein Objekt von einer Klasse brauche, mache ich alles statisch.

Methoden sollte man, vereinfacht gesagt, statisch machen, wenn sie keinen internen Zustand eines Objektes verändern (sondern nur "Utility-Methoden" sind, die eine Eingabe bekommen und eine Ausgabe ausspucken)

Das Kriterium "ICH brauche nur eine Instanz" ist aber unbdeutend. (Das Singleton verwendet man, wenn es immer nur eine Instanz geben DARF). Jemand anderes braucht vielleicht drei oder 143 Instanzen davon.
 

muckelzwerg

Bekanntes Mitglied
Ja, "kein zustandsabhängiges Verhalten" seh ich auch als ersten Anhaltspunkt.
Sowas wie die ganzen Funktionen in der Matheklasse.

Ich bin aber mit statischen Methoden nicht so ganz im Reinen. Auf der einen Seite schreibe ich schon fast reflexartig alles so modular und unabhängig wie möglich, auf der anderen Seite fühlt es sich für mich komisch an, wenn "gewöhnliche" Klassenmethoden statisch sind.
Das ist für mich irgendwie ein Widerspruch. Ich bilde Klassen, um die Funktionalität logisch zu kapseln und dann verwende ich darin wieder ein Konzept, dass eher gegen die einzelnen Kapseln gerichtet ist?
Meist verschiebe ich das dann in Hilfsklassen, mit nur statischen Methoden.
 

davidh38

Bekanntes Mitglied
Methoden sollte man, vereinfacht gesagt, statisch machen, wenn sie keinen internen Zustand eines Objektes verändern (sondern nur "Utility-Methoden" sind, die eine Eingabe bekommen und eine Ausgabe ausspucken)

Das Kriterium "ICH brauche nur eine Instanz" ist aber unbdeutend. (Das Singleton verwendet man, wenn es immer nur eine Instanz geben DARF). Jemand anderes braucht vielleicht drei oder 143 Instanzen davon.

Genau, das macht diese Klasse, sie nimmt einen String und formatiert in nach den Bedürfnissen des jeweiligen Funktionsaufrufers. Vielen Dank.
 

Marco13

Top Contributor
Auf der einen Seite schreibe ich schon fast reflexartig alles so modular und unabhängig wie möglich, auf der anderen Seite fühlt es sich für mich komisch an, wenn "gewöhnliche" Klassenmethoden statisch sind.
Das ist für mich irgendwie ein Widerspruch. Ich bilde Klassen, um die Funktionalität logisch zu kapseln und dann verwende ich darin wieder ein Konzept, dass eher gegen die einzelnen Kapseln gerichtet ist?
Meist verschiebe ich das dann in Hilfsklassen, mit nur statischen Methoden.

Ja, Teile davon waren für mich Anlass zu dem von schalentier verlinkten Thread. Aber ich sehe keinen grundsätzlichen Widerspruch zu Kapselung. Im Gegenteil: Bei einer statischen Methode hat man eine dedizierte, abgeschlossene Funktion, die immer und überall aufgerufen werden kann, ohne dass man sich über Zustände, Threads oder sonstiges Gedanken machen muss. Gekapselter geht's eigentlich nicht ;) Ich finde aber auch, dass statische Methoden nur in bestimmten Fällen (d.h. allgemein eher nicht) Teil der öffentlichen API sein sollten. Eine statische Utility-Methode sollte IMHO (!) auch in einer Utility-Klasse liegen, und nicht in "irgendeiner" Klasse, die "irgendwie" mit dieser Methode zu tun hat.

Vermutlich bezog sich der angedeutete Widerspruch darauf, dass statische Methoden eben per se nicht objektorientiert sind. Aber in gewissen Grenzen finde ich gerade das einen Vorteil: Die Methoden sind "orthogonal" zu den OO-Konzepten. Schließlich spricht aus OO-Sicht nichts dagegen, wenn man sowas machen würde wie
Java:
class SortableList extends ArrayList
{
    public void sort()
    {
        Collection.sort(this);
    }
}
(Ja, da spricht DOCH was dagegen, nämlich dass das Ding "ArrayList" erweitert ;) es ging nur darum, ) ... dass dort eine Funktion ausschließlich durch das Delegieren an eine statische Funktion implementiert ist. Das sieht man ja an der Schnittstelle nicht. Man kann nach wie vor Polymorphie anwenden usw.

Und wie im anderen Thread angedeutet, werden solche statischen Delegierungs-Methoden in den nächsten Java-Versionen vermutlich eher an Bedeutung (und vor allem auch: sprachlicher Unterstützung) gewinnen. D.h. für das Konkrete Beispiel könnte es sogar so sein, dass das java.util.List interface erweitert wird um eine
Java:
interface List<T> ...
{
    public extension void sort()
        default Collections.sort;
}
so dass jede List nachher eine "sort" Methode hat, ohne dass Clients, die schon ihre eigene List-Implementierung haben, dieses "sort" selbst dazuimplementieren müßten.

Aber das schweift ab. Und natürlich sollte das mit "sort" nur ein Beispiel sein, das so sicher nicht umgesetzt wird.
 

muckelzwerg

Bekanntes Mitglied
Sehe ich ziemlich ähnlich.
Bei statischen Methoden stell ich mir sofort die Frage, ob die Methode wirklich noch zu der Klasse gehört.
Gehört eine Sortiermethode wirklich zu der Liste, die von ihr sortiert wird?
Gerade bei Java kann man in ein paar kurzen Überlegungen meist eine Abstraktion finden, die dann laut nach einem Interface ruft.
So in etwa wie bei den Komparatoren.
Wenn ich eine Methode statisch mache, dann möchte ich sie meist in eine entsprechende Hilfsklasse auslagern. (Wie bei Collections z.B.)
Darauf verzichte ich dann vielleicht mal, wenn es zu aufwändig ist und für ein "kleines" Objekt nicht lohnt.
Aber grundsätzlich hab ich bei statischen Methoden meist den Drang es so "ausgelagert" wir möglich zu machen. So nach dem Motto "Ich konnte die Funktionalität ja auch übers Netzwerk bekommen, oder es in Hardware brutzeln und auf der CPU haben oder ..."
(ist etwas extrem)

Wenn eine Methode statisch wird, dann fällt sie für mich aus der Klasse und der Arbeit mit dem zugehörigen Objekt raus. Es gibt natürlich ausnahmen, wie z.B. Singletons und ähnliche Sachen.
Aber meist führt ein Weiterentwickeln der Software doch schnell dazu, dass statische Methoden einen neuen Ort haben, an den sie besser passen würden.
Ich hab vor einer Weile ein paar UI-Widgets mit LUA gebastelt. Das Rendering lief über Java2D. Erst war die "render()"-Funktion in der Klasse jedes Widgets. (klar Prototyp, Gebastel ...).
Dann wurde sie irgendwann statisch, eben weil das Rendering zustandslos abläuft, bzw. der Zustand frisch gelesen wird.
Und sobald es ein paar Widgets mehr waren, hab ich dann wieder alle Rendermethoden rausgeworfen, ein Interface gebaut und eine Renderer-Klasse geschrieben, die für jedes Objekt die passende Funktion hat.
Wieder etwas später kam der Gedanke zwischen Java2D und anderen Renderern wechseln zu können, was dann natürlich viel angenehmer zu machen war.

Worauf ich hinaus will ist, dass ich die entwickelten Module manchmal zu "groß" finde. Oft macht man innerhalb der Klassen genau das Gegenteil von der Ordnung, die man z.B. mit MVC gerne erreichen möchte.
Da hat man dann diese Alleskönner und den Code "schön beeinander". Und ein paar Wochen später könnte man die eine Funktion aus Klasse X auch sehr gut für Objekte vom Typ Y gebrauchen und schon geht das Gefummel wieder los.
Es ist schon sinnvoll, dass man logische Kapseln um zusammengehörige Funktionalität hat, aber man sollte versuchen diese Kapseln nicht mit den Klassen gleichzusetzen. Dann lieber einen Schritt höhergehen und gleich eine Bibliothek daraus machen.
Gerade bei Java bietet sich sowas ja an.

Statische Methoden auszulagern und dann über nichtstatische Klassenmethoden aufzurufen finde ich ziemlich "gut".
Im anderen Thread wurde die "sin()"-Funktion angesprochen und dass man die wohl nicht unbedingt ersetzen würde.
Solche Mathematischen Funktionen umzubiegen ist aber bei vielen Echtzeitverfahren z.B. in der Digitalen Bildverarbeitung oft Standard.
Es kann gut sein, dass man von einem auf den anderen Moment alle Winkelfunktionen durch Tabellen ersetzen will.
Wenn man überall direkt die Mathelib genutzt hat, wird das eklig. Hat man das nochmal gekapselt schaltet man zentral um. (oder auch bedarfsweise z.B. über Typprüfung, Interfaces etc.)
 
Zuletzt bearbeitet:

Eistoeter

Mitglied
1) Es darf nur genau 1 Objekt von einer Klasse existieren -> Singleton-Pattern
Hier habe ich vor allem festgestellt, dass es wichtig ist wie man "DARF" versteht. Wenn zwar nur ein Objekt existieren darf, aber das alleine in meiner Kontrolle liegt, sprich außer mir kann niemand ein Objekt davon instanziieren weil die Sichtbarkeit der Klasse beschränkt ist, dann braucht man auch kein Singleton zu machen.

2) Du hast eine Klasse, deren Methoden oder Variablen von überall aus oder von sehr vielen verschiedenen Stellen aus erreichbar sein sollen -> public static
(die Alternative ist es a) ein Objekt irgendwo zu erzeugen und überall als Parameter in Methoden / Konstruktoren herumzureichen oder b) jedes mal ein neues Objekt von der Klasse zu erzeugen)

Beispiel für 2) wäre eine Klasse ArgumentCheck mit einer Methode notNull(Object o). Diese wird zu Beginn von sämtlichen Methoden verwendet, um zu testen, dass Parameter nicht null sind. Jetzt könntest du hergehen und immer sagen new ArgumentCheck().notNull(o); ... komfortabler ist aber ArgumentCheck.notNull(o), also macht man's statisch. Außerdem würden bei ersterer Variante sehr viele Objekt erzeugt, was für Performance nicht so gut ist. Performance sollte man aber nicht als Kriterium für statisch / nicht-statisch hernehmen.
 
Zuletzt bearbeitet:

muckelzwerg

Bekanntes Mitglied
Beim Singleton kann man sich über die Zugriffskontrolle oft wirklich streiten. Bei einem abgeschlossenen Projekt mit passenden Sichtbereichen ist das Verhindern von "unerlaubter Erzeugung" dann vielleicht nur noch akademisch zu sehen.
Bei dem was ich bisher gemacht habe, lag der Fokus von Singletons darin, race-conditions bei der Initialisierung von multithreaded Anwendungen zu verhindern.
Da kann man manchmal einfach nicht wissen, wann welches Objekt wirklich erzeugt wird und wo es zuerst passiert.
Mit dem Singleton lässt man dann alle überzähligen Aufrufe ins Leere laufen und hat Ruhe.
 

Marco13

Top Contributor
2) Du hast eine Klasse, deren Methoden oder Variablen von überall aus oder von sehr vielen verschiedenen Stellen aus erreichbar sein sollen -> public static

Bei den Methoden ist es klar, das sind die angesprochenen Utility-Methoden. Aber bei Variablen ist das IMHO ein no-go, weil genau dadurch ja der Zustand unkontrollierbar über das ganze Programm verschmiert wird....
 
M

maki

Gast
Mit dem Singleton lässt man dann alle überzähligen Aufrufe ins Leere laufen und hat Ruhe.
Dafür hat man dann das Singleton an der Backe, SoC wird verletzt weil Erzeugung und Zugriff gleichzeitig geregelt werden, dann der static Zugriff... jedes DI Framework bietet bessere Alternativen um ein Objekt nur einmal zu erzeugen, sogar schon "pseudo-standartisiert" mit javax.inject.Singleton
 
M

maki

Gast
SoC steht für "Seperation of Concerns", das Problem beim GoF Singleton: Erzeugung, Zugriff und eigentliche Logik stehen alle in einer Klasse.

Das Problem mit dem static Zugriff: Schlecht fürs testen, gibt nicht viele Unittest Frameworks die es erlauben, statische Aufrufe "umzubiegen".
 

muckelzwerg

Bekanntes Mitglied
Für mich bedeutet das "System on a Chip". ;)
Inwiefern liegt das denn alles zusammen in einer Klasse? "Meine" Singletons sind z.B. sowas wie eine Registry, um Zugriff auf Konfigurationsparameter zu bekommen und bestimmte "globale" Instanzen der Anwendung anzusprechen.
Ich seh nicht wo da "alles zusammen" ist.

Beim Testen meinst Du wegen Überschreiben? Das Problem hatte ich z.B. bei Junit noch nicht. Aber ich mach in der Richtung auch nicht viel. Das ist dann natürlich unpraktisch.
 
M

maki

Gast
Inwiefern liegt das denn alles zusammen in einer Klasse?
Nun, wenn du ein GoF Singleton geschrieben hast, dann hast du eine statische Methode (zB. getInstance) mit der man auf das Singleton zugreifen kann, dann wohl einen privaten Konstruktor, wie ein Objekt erzeugt wird, ist unweigerlich damit verbunden, wie man es erhält, und dann hat deine Klasse wohl noch irgendeine Funktionialität ;)
Alles in einem Singleton...

Zum vergleich, ein Singleton zB. in Guice:
Java:
@Singleton
public class Anything {
...
}
Es reicht wenn @Singleton dasteht, keine statische getInstance Methode, kein privater Konstruktor nötig.

und bestimmte "globale" Instanzen der Anwendung anzusprechen.
So wie "globale Variable" vielleicht?
Das wäre nämlich ein eindeutiger Missbrauch eines Singletons, selbst nach GoF regeln.

Beim Testen meinst Du wegen Überschreiben? Das Problem hatte ich z.B. bei Junit noch nicht. Aber ich mach in der Richtung auch nicht viel.
Offensichtlich machst du da nicht viel mit, denn ein GoF Singleton ist definitiv ein "Showstopper" wenn es ums testen geht (ohne EasyMock zB.).
 

muckelzwerg

Bekanntes Mitglied
Hm, also da verstehe ich das Problem nicht. Wo willst Du die Funktionalität denn sonst hinlegen? Wo ist der Unterschied zu allen anderen Klassen?

Ich weiß nicht, was Du mit "globaler Variable" meinst. Ich hab dort zum Beispiel Werte aus Konfigurationsdateien hinterlegt.
Oder Laufzeitinformationen wie zum Beispiel den aktuellen Modus der Applikation. Dazu Instanzen die von "überall" genutzt werden können und z.B. begrenzte Ressourcen kapseln (Pools für Threads/Speicher, ...)

Ist einfach nicht so mein Job. Und die Leute, die sowas machen/gemacht haben, kannten sich z.B. mit den entsprechenden Mocks eigentlich ziemlich gut aus. Da kam sowas als Problem nie wirklich auf.
Mit cunit und junit hatte ich noch am meisten zu tun, als wir an einer Implementierung vom DDS (OMG) geschraubt haben. Aber auch da war ich nicht so wahnsinnig tief drin.
 

tfa

Top Contributor
Ich weiß nicht, was Du mit "globaler Variable" meinst. Ich hab dort zum Beispiel Werte aus Konfigurationsdateien hinterlegt.
Oder Laufzeitinformationen wie zum Beispiel den aktuellen Modus der Applikation. Dazu Instanzen die von "überall" genutzt werden können und z.B. begrenzte Ressourcen kapseln (Pools für Threads/Speicher, ...)
Viele Leute "missbrauchen" das Singleton-Pattern eben nur als globale Variable, weil das so schön praktisch ist, dass man von überall drauf zugreifen kann. Der eigentlich Zweck, nämlich zu verhindern, dass es mehr als ein Objekt gibt, ist da völlig nebensächlich. Ich kann mir durchaus Fälle vorstellen, wo man mehr als einen Thread- oder Connection-Pool hat. Oder viele Konfigurationen. Und wenn man dann von Singleton auf was vernünftiges Umstellen will, sitzt man erstmal tagelang da, um seinen Code zu refaktorieren und die globalen Referenzen weg zu bekommen. Da sind die angesprochenen DI-Frameworks schon sehr viel praktischer. Von derTestbarkeit ganz zu schweigen.
 

muckelzwerg

Bekanntes Mitglied
Das versteh ich nicht. Wenn ich nur eine "Registry" brauche, dann bau ich doch auch nur das. Die hol ich mir dann "am höchsten Punkt", von mir aus auch über eine statische Methode.
Aber wieso sollte jemand auf die Idee kommen den Singletonkram mit privatem Konstruktor etc. noch dazubasteln, wenn sich dadurch gar nichts ändert?
 
M

maki

Gast
Da kam sowas als Problem nie wirklich auf.
Klar, wenn man nicht isoliert tested, dann gibt es auch keine Probleme beim testen wenn Singletons involviert sind ;)

Wenn ich nur eine "Registry" brauche, dann bau ich doch auch nur das. Die hol ich mir dann "am höchsten Punkt", von mir aus auch über eine statische Methode.
Ich nehme an, dass du noch nicht mit DI gearbeitet hast, das "holen" an sich wird überflüssig, weil die Objekte schon alles bekommen was sie brauchen, ohne statische Methoden von anderen Klassen aufzurufen, weniger Kopplung/direkte abhängigkeiten (loose coupling).

Aber wieso sollte jemand auf die Idee kommen den Singletonkram mit privatem Konstruktor etc. noch dazubasteln, wenn sich dadurch gar nichts ändert?
Tja, wieso kommen Leute auf die Idee ein GoF Singleton zu nutzen?
"Wenn man nur einen Hammer hat, sieht jedes Problem wie ein Nagel aus"

Singletons haben eben ihre Nachteile, dass sollte man schon dazusagen wenn man sie emphfielt.
 

schalentier

Gesperrter Benutzer
Fuer mich ist das Problem mit statischen Methoden, dass zwei (getrennt ziemlich praktische) Sprachfeatures einer Programmiersprache miteinander vermischt sind und man nur beide gleichzeitig nutzen kann.

1. Methoden auf Klassenebene. Das waere ein aeussert nuetzliches Feature, wenn man diese auch normal ueberschreiben koennte. Damit waere beispielsweise ein Factory Pattern total simpel hingeschrieben:
Java:
public abstract class Base {
   public Base Base.create(int type) {
      switch( type ) {
         case 1: return new Foo1();
         case 2: return new Foo2();
         default: throw IllegalArgumentException();
      }
   }
}
public class Foo1 extends Base {
}

In einem Test koennte man jetzt diese create Methode ueberschreiben und z.B. einen Mock zurueckliefern lassen. Nebenbei koennte man auch auf das Keyword [c]new[/c] verzichten und das einfach als Klassenmethode umsetzen.

2. statische Methoden (== Funktionen im math. Sinn). Also solche, die fuer einen gegebenen Input immer den gleichen Output liefern und keinerlei Zustaende irgendwo ablegen muessen. Das koennte sinnvoll sein, weil man die z.B. direkt "inlinen" koennte -> Performance.

@muckelzwerg: Konfiguration ist ein schoenes (Negativ-) Beispiel. Stell dir eine Methode vor, die dieses statische Konfigurations-Etwas benutzt, welches die Konfiguration aus einer Propertiesdatei ausliest. Wenn du diese jetzt testen willst, muss in jedem Test diese Datei geladen werden. Das ist erstens langsam (HD Zugriff) und zweitens muss immer dafuer gesorgt werden, dass eine entsprechende Datei im korrekten Pfad rumliegt. Haette man eine normale, nicht-statische Klasse fuer die Konfiguration, koennte man dem Test eine entsprechend sinnvoll konfigurierte Testinstanz unterschieben. Damit kann man auch erreichen, dass alles fuer den Test notwendige in genau einer Klasse (=Datei) zusammen definiert ist.
 

muckelzwerg

Bekanntes Mitglied
@ maki, naja es gibt immer irgendwelche Leute, die seltsame Dinge machen. Sich an denen zu orientieren find ich jetzt nicht so passend für so ein Thema.

@ schalentier:
Wieso muss die Datei jedesmal geladen werden?
Und wenn Du eben mit Konfigurationen in Dateien arbeitest, wie willst Du das dann umgehen, wenn Du das Pattern wechselst?
Ich seh da keinen Zusammenhang zum Singleton. Ob ich eine Konfigurationsdatei verwende ist doch nicht von "static" abhängig.
Etwas ganz anderes tun und sich dann zu freuen, dass man andere Probleme hat, bringts ja nun auch nicht.
 

tfa

Top Contributor
Wieso muss die Datei jedesmal geladen werden?
Und wenn Du eben mit Konfigurationen in Dateien arbeitest, wie willst Du das dann umgehen, wenn Du das Pattern wechselst?
Ich seh da keinen Zusammenhang zum Singleton. Ob ich eine Konfigurationsdatei verwende ist doch nicht von "static" abhängig.
Etwas ganz anderes tun und sich dann zu freuen, dass man andere Probleme hat, bringts ja nun auch nicht.


Stell dir vor, du hast eine Methode, die die Konfig-Daten benötigt. Diese soll unitgetestet werden:
Java:
public class MitGoFSingleton {

	public String formatiereDatenGemaessBenutzereinstellungen() {
		UserProperties props = UserProperties.getSingletonInstance();
		...[aufwendige Berechnungen]...
		return result;
	}
}
Diese Methode ist fest mit deinem Singleton-Objekt verdrahtet. UserProperties lädt die Einstellungen meinetwegen aus einer Datei oder auch aus einer Datenbank. Das hat einige Nachteile:
  • DB-oder File-Zugriff dauert verhältnismäßig lang. Das möchte man in Unit-Tests nicht haben.
  • Man testet nicht nur die Methode, sondern auch den File- bzw. DB-Zugriff.
  • Möglicherweise hat man in der Testumgebung gar keinen Zugriff auf die DB bzw. Dateien (wenn die Sache z.B. auf einem Continous-Integration-Server läuft).
  • Man weiß nie so recht, was in der Property-Datei oder der entsprechenden Datenbank steht. Das kann sich dauernd ändern. Für Tests braucht man reproduzierbare Daten.
  • Was soll man tun, wenn man verschiedene Testkonfigurationen für verschiedene Tests haben will (es gibt vielleicht 100 solcher Methoden).

Wenn man das statische Singleton entfernt und das ganze über DI löst, sieht es schon besser aus:
Java:
public class MitDependencyInjection {

	@Autowired
	private UserPropertiesProvider propsProvider;
	
	public String formatiereDatenGemaessBenutzereinstellungen() {
		UserProperties props = propsProvider.getProperties();
		...[aufwendige Berechnungen]...
		return result;
	}
}
Hier sorgt das DI-Framework dafür, dass wir unsere passenden UserProperties bekommen. Der Code holt sie sich nicht mehr. Das ist Inversion of Control.
Welche Art UserProperties der Provider liefert kann jetzt frei definiert werden.
Für den Test gibt es einen "de.meinprojekt.test.DummyUserPropertiesProvider", der reproduzierbare Testdaten liefert. Im normalen Betrieb nimmt man den "de.meinprojekt.DatabaseUserPropertiesProvider", der die Einstellungen aus der DB lädt.
Vielleicht hat man irgendwann noch eine Offline-Variante seiner Software, die ohne Netzwerk- und DB-Zugriff funktionieren soll. Dann kann man sich eine "de.meinprojekt.local.FileUserPropertiesProvider"-Klasse schreiben und ganz einfach vom DI injizieren lassen.

Wer DI einmal ausprobiert hat, möchte es nicht mehr missen.
 
M

maki

Gast
@ maki, naja es gibt immer irgendwelche Leute, die seltsame Dinge machen. Sich an denen zu orientieren find ich jetzt nicht so passend für so ein Thema.
Eben, "Leute" die Singletons schreiben sind zB. kein gutes Vorbild.
Mittlerweile gibt es DI als JSR vom JCP, für EJB3, JSF, Spring, Guice, etc. pp.

Es gibt keinen Grund mehr warum man Singletons schreibt, ausser dass man es nicht besser weiss.
 

muckelzwerg

Bekanntes Mitglied
tfa, ich verstehe nach wie vor nicht, was das Auslesen der Datei (oder von mir aus auch DB) mit dem Pattern zu tun hat.
Irgendwann muss mal ein "setValue()" gemacht werden. Ob Du nun Singletons, DI, oder was auch immer verwendest, wenn die Konfiguration in Flatfiles liegt, musst Du sie auch dort holen.
Wenn Du sie statt dessen in die Tests mitaufnimmst fein. Dann kannst Du bei jeder anderen Hashmap genauso die Daten einfügen, wie bei der Hashmap der von DI kontrollierten Config.
Das würde ja sonst bedeuten, das Pattern zwingt Dir auf, ob Du eine Datei oder Datenbank verwendest. Und das ist Quatsch. Das wissen wir beide und das hast Du ja auch selbst indirekt bei Dir stehen.
Schalentier hat gesagt, das Laden der Konfigurationsdateien wäre langsam und man müsste dafür sorgen, dass sie überhaupt vorhanden sind.
Ich bin der Meinung, dass beides keinerlei Zusammenhang damit hat, ob DI verwendet wird oder nicht. Egal mit welchen Pattern ich meine Unit-Tests mache, muss ich dafür sorgen, dass die gewünschte Konfiguration vorhanden ist.
Und ob ich das Laden der Konfiguration in den Test miteinschließe, oder umgehe und um die Ladezeit zu sparen (wieviel macht das aus? reales problem? ICH weiß es nicht) in den Test mit reinschreibe, ist ebenfalls nicht von DI, Singleton oder was auch immer abhängig.
Die Entscheidung, ob ich meine Konfiguration in Dateien haben will wird doch nicht vom Pattern vorgeschrieben, sondern davon, was für meine Anwendung gewünscht ist.
Und wenn ich teste, muss ich damit dann eben umgehen. Ist ja nicht so, dass man dann auf einmal blöd, unflexibel und faul wird, wenn man vorher die tollsten Sachen gebaut hat.
 

Landei

Top Contributor
tfa, ich verstehe nach wie vor nicht, was das Auslesen der Datei (oder von mir aus auch DB) mit dem Pattern zu tun hat.
Irgendwann muss mal ein "setValue()" gemacht werden. Ob Du nun Singletons, DI, oder was auch immer verwendest, wenn die Konfiguration in Flatfiles liegt, musst Du sie auch dort holen.

Es ist aber ein riesen Unterschied, ob ich in dazu fest verdrahteten Produktionscode ändern muss, oder in meiner Testumgebung.

Ich kann dir mal ein Beispiel aus meiner Praxis nennen. Wir haben noch EJB2 mit einem eigenen Framework. Eigentlich alles hübsch mit viel Interfaces, Facade-Pattern und so weiter. Der Blödsinn ist, dass sich der Produktionscode die Homes der EJBs über ein Singleton (eine tolle Framework-Klasse namens BusinessHomeFactory) holt. Eigentlich eine nette Abkürzung bei der ganzen Zeremonie. Aber damit haben wir nicht die geringste Chance, EJBs ohne Application Server zu testen. Jedes bescheuerte EJB benutzt das Singleton, was selber wieder hübsch mit Security und JNDI und weiß der Himmel noch verdrahtet ist.

Einmal eine Kleinigkeit geändert, dann geht der ganze Mist von vorne los: build, Kaffe holen, deploy, Kaffe trinken, auf java-forum surfen, kurz bei Dilbert reinschauen, Kollegen den Strip schicken und dann ist das Schweineding endlich oben und man kann man die Änderung testen - nach mindestens 20 Minuten. Aber in vielen Fällen bräuchte man den App-Server und die Datenbank gar nicht, da könnte das Home zwei, drei Fake-EJBs liefern, die zum Testen ausreichen würden. Bäks.
 

muckelzwerg

Bekanntes Mitglied
Aber das zwingt euch doch euer Singleton nicht auf. Spring benutzt doch selbst auch welche.
Du kannst euer Singleton ja auf eine synchronisierte Map umstellen und schauen, ob sich dann was verbessert.
Natürlich ist es unschön, wenn ihr solche Probleme habt. Aber diese Dinge besser zu machen, ist doch nicht erst mit Spring und DI plötzlich möglich geworden.
Würdest Du wirklich sagen, dass eure Schwierigkeiten an dem Wörtchen "static" irgendwo im Code hängen?
 

schalentier

Gesperrter Benutzer
Würdest Du wirklich sagen, dass eure Schwierigkeiten an dem Wörtchen "static" irgendwo im Code hängen?

Ja.

Du musst ja im Produktivcode, also der zu testenden Methode sowas schreiben:
Java:
public String methodToTest(...) {
   String result = BusinessHomeFactory.getInstance().getComplexBusinessLogic().doIt();
   // do something
   return result;
}

Zeile 2 macht nun wie Landei beschrieben hat, jede Menge JEE Kram, hat viele Abhaengigkeiten und braucht eben eine gewisse Zeit.

Fuer den Test ist dieser Aufruf aber moeglicherweise voellig irrelevant, eine Mockmethode, die z.B. immer "TestString" zurueckliefert, wuerde vielleicht ausreichen.

Wie willst du jetzt diesem (Java-) Singleton die gemockete Methode unterschieben? Du kannst getInstance() nicht ueberschreiben (ist static), du kannst zwar getComplexBusinessLogic() ueberschreiben, aber der Aufruf in der zu testenden Methode geht immer an die BusinessHomeFactory#getComplexBusinessLogic() Methode.

Ja, du kannst dann Produktivcode mit Testcode vermischen, was nicht gewollt sein kann. Da kommt dann sowas raus:
Java:
public class BusinessHomeFactory {
   //static getInstance()
   public ComplexBusinessLogic getComplexBusinessLogic() {
      if( inTestMode() ) { return new MockedComplexBusinessLogic(); } else { // do JNDI lookup }
   }
}

Zudem wird jetzt im Test IMMER das Mocked Objekt geliefert, aber was machst du jetzt wenn du im zweiten Test ein anderes Mockobjekt haben moechtest und im dritten Test das richtige JNDI Ding?

Und Schuld an allem ist nur die von mir beschriebene Doppelbelegung von static.
 

Landei

Top Contributor
Aber das zwingt euch doch euer Singleton nicht auf. Spring benutzt doch selbst auch welche.
Du kannst euer Singleton ja auf eine synchronisierte Map umstellen und schauen, ob sich dann was verbessert.

Häh? Das Ding macht Lookups mit JNDI am lebenden App-Server, nix mit "synchronisierter Map".

Natürlich ist es unschön, wenn ihr solche Probleme habt. Aber diese Dinge besser zu machen, ist doch nicht erst mit Spring und DI plötzlich möglich geworden.
Richtig, könnte man auch ohne DI besser machen. Habe ich aber leider keine Kontrolle drüber, unser Projekt ist international (federführend sind unsere amerikanischen Freunde, die sich grundsätzlich nichts sagen lassen) und leidet an permanenter Featuritis: "Werk XY braucht unbedingt das und das, lass uns bloß mit Infrastruktur in Ruhe"

Würdest Du wirklich sagen, dass eure Schwierigkeiten an dem Wörtchen "static" irgendwo im Code hängen?
Ja. Siehe Schalentiers Antwort.
 

muckelzwerg

Bekanntes Mitglied
Landei, ich meine, dass Du eure Singletons doch auch so verwalten kannst, wie z.B. Spring das mit seinen Singletons macht.
(DefaultSingletonBeanRegistry ...)
Aber das wird nichts an Deinen wahren Problemen mit den "amerikansichen Freunden, die sich nichts sagen lassen" ändern.


Ich komme mir grad so vor, als hätte ich gesagt, eure Lieblingsspielekonsole wäre sch...
Vielleicht schaut ihr nochmal, was ICH zu Anfang über Singletons gesagt habe und geht weniger nach dem, was "Leute" machen. ;)
 

tfa

Top Contributor
Landei, ich meine, dass Du eure Singletons doch auch so verwalten kannst, wie z.B. Spring das mit seinen Singletons macht.
(DefaultSingletonBeanRegistry ...)
Das wollen wir doch. Siehe mein Beispiel oben. Nur haben diese Spring-Singletons nichts mit dem statisch verdrahteten, GoF-Pattern "Singleton" zu tun. Das ist was völlig anderes.
 

muckelzwerg

Bekanntes Mitglied
Oh man. Genau deswegen hab ich es doch geschrieben. -_-
Solange er nur ein einziges Singleton hat, ist eine ganze Map wie sie Spring verwendet zwar Overkill, aber das kann er ja passend reduzieren.
Ich denke das Thema ist durch. Wir verpulvern sonst nur unsere Zeit.
Gruß und tschüss. :)
 

tfa

Top Contributor
Aber den Unterschied zwischen statischem Singleton-Pattern und "Singelton-Scope" bei DI hast du schon verstanden? Ich dachte darum ging es.
 

muckelzwerg

Bekanntes Mitglied
Wenn Dir das aus dem, was ich dazu gerade geschrieben habe, nicht klar wird, dann macht es doch wirklich keinen Sinn, dass wir uns da weiter zusetzen. (verschwendet Doch nur unser beider Zeit)
Ich hab sicher nicht so viel Übung damit wie Du, aber blöd bin ich nicht. Und dieses Getue, als würde ich hier die Weltherrschaft der Singletons als "globale Variable" proklamieren, ist einfach nur käsig.
Wenn Du mal nachliest, wirst Du sehen, dass ich Singletons wegen "Race Conditions" angesprochen habe und nicht weil es so "toll" ist eine Instanz über eine statische Methode zu globalisieren.. Du wirst auch finden, dass ich maki bei den Testing-Problemen zugestimmt habe.
Und die angesprochene, synchronisierte Map findest Du im Spring Source.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
M Exceptions - wann / wie verwenden? Allgemeine Java-Themen 4
LimDul Spezifkation, wann es deprecation Warnings gibt Allgemeine Java-Themen 1
N Streams wann .filtern? Allgemeine Java-Themen 2
perlenfischer1984 Wann ist ein Parameter Check sinnvoll Allgemeine Java-Themen 7
T GUICE- Dependency Injection- WANN nutze ich Providers? Allgemeine Java-Themen 2
B Erkennen, wann Prozess beendet ist, dann Thread beenden. Allgemeine Java-Themen 6
Rudolf Wann System.exit und wann dispose? Allgemeine Java-Themen 9
L Checkstyle: Wann ist eine Methode für Vererbung entworfen? Allgemeine Java-Themen 13
X Wann ist Runtime.getRuntime().exec mit Copy fertig? Allgemeine Java-Themen 10
M Wann ist MVC sinnvoll? Allgemeine Java-Themen 14
M Wann Membermethoden, wann statische Utility-Methoden? Allgemeine Java-Themen 24
Ark Wann 64 Bit-Befehle im Einsatz? Allgemeine Java-Themen 6
G Wann normale Exception und wann Runtimeexception Allgemeine Java-Themen 12
Y Wann folgende Technologien benutzen Allgemeine Java-Themen 5
G Parameter oder Attribut (wann nehme ich was?) Allgemeine Java-Themen 12
M Wann verwendet man PropertyChangedEvents, wann eigene? Allgemeine Java-Themen 3
F Wann und wie Exceptions einsetzen? Allgemeine Java-Themen 13
G Wann statische Methoden, statische Attributen? Allgemeine Java-Themen 7
G Ab wann Datenbank verwenden Allgemeine Java-Themen 15
B Wann Interface und wann Adapter Allgemeine Java-Themen 4
B ObjectInputStream - Wann ist Ende erreicht? Allgemeine Java-Themen 10
D Wann ist das ergebnis einer Rechnung eine Double? Allgemeine Java-Themen 7
M Maximal verfügbarer Hauptspeicher? Ab wann wird ausgelagert? Allgemeine Java-Themen 13
P Wann kommt denn nun 1.5 überhaupt? Allgemeine Java-Themen 6
Zrebna Wieso sollte man Null-Prüfungen nicht mit Optional-Objekten nutzen? Allgemeine Java-Themen 13
MiMa Was sollte man ins JavaDoc implementieren?? Allgemeine Java-Themen 17
MiMa Wie sollte am besten ein Datum gespeichert werden? Allgemeine Java-Themen 8
R In der Ausgabe sollte anstelle des obersten Sterns ein "+" stehen nur scheitere ich bei der Implementierung Allgemeine Java-Themen 9
T Multithreading: Wie viele Threads sollte ich erstellen? Allgemeine Java-Themen 12
J wie sollte man sinnvoll seinen Code aufteilen Allgemeine Java-Themen 6
R Input/Output java.io.EOFException, obwohl sie abgefangen sein sollte? Allgemeine Java-Themen 3
DaniSahne96 Threads Code funktioniert nicht wie er sollte Allgemeine Java-Themen 9
R Syntax Error, der keiner sein sollte Allgemeine Java-Themen 12
V Fortbildungen oder Zertifikate in Java die man haben sollte? Allgemeine Java-Themen 17
André B. Was sollte eine Template Engine können? Allgemeine Java-Themen 3
A Warum gibts die Main und was sollte drin stehen? Allgemeine Java-Themen 31
B Was sollte ich benutzen Vektor oder ArrayList? Allgemeine Java-Themen 5
A Weshalb man Parameter auf Gültigkeit prüfen sollte Allgemeine Java-Themen 6
D NullPointerException wo keine sein sollte. Allgemeine Java-Themen 2
temi Private statische Hilfsmethoden Allgemeine Java-Themen 33
T statische Variable und nicht-statische Methode Allgemeine Java-Themen 2
rentasad Design-Frage - Interfaces, Klassen, statische Methoden Allgemeine Java-Themen 3
P "Overriden statische Methode" Statische Methode die vererbt wird Allgemeine Java-Themen 5
N Threads statische Methoden in Threads Allgemeine Java-Themen 5
M Zeiger auf statische Variable Allgemeine Java-Themen 1
S Kapselung Statische Helper Klassen Allgemeine Java-Themen 5
C Classloading und statische Variablen Allgemeine Java-Themen 2
faetzminator statische Variablen in Interface - Vererbung? Allgemeine Java-Themen 9
J Statische Variablen, Threadübergreifend. Allgemeine Java-Themen 4
R Statische Klasse: Best practice mit flags (2) Allgemeine Java-Themen 3
N Klasse rausfinden, an der eine statische Methode aufgerufen wurde ? Allgemeine Java-Themen 10
R statische initialisierer Allgemeine Java-Themen 7
S statische Methoden und Vererbung Allgemeine Java-Themen 6
M Zwingen eine statische Methode zu importieren Allgemeine Java-Themen 5
heart_disease Designfrage: Statische Konfigurationsklasse Allgemeine Java-Themen 10
S statische Interfaces..? Allgemeine Java-Themen 6
S Innere Klassen und die statische Methode access$x Allgemeine Java-Themen 5
S Statische Methoden in abstrakte Klassen deklarieren? Allgemeine Java-Themen 17
M Paralleler Zugriff auf statische Methode Allgemeine Java-Themen 5
J Statische Methoden in Interfaces? Allgemeine Java-Themen 10
F Statische Methode in abstrakter Superklasse definieren Allgemeine Java-Themen 4
B Statische Methode? Komisch. Allgemeine Java-Themen 5
G Statische Methoden erzwingen Allgemeine Java-Themen 2
H Zugriff auf statische Variable synchronisieren Allgemeine Java-Themen 4
A [SOLVED] Classpath und statische Variablen Allgemeine Java-Themen 6
S Tiefe Kopie einer Baumstruktur als statische Methode Allgemeine Java-Themen 8
M statische Methode per reflection aufrufen Allgemeine Java-Themen 2
M statische regex und vergleiche oder immer wieder compilen Allgemeine Java-Themen 2
S Statische Methode oder nicht? Allgemeine Java-Themen 5
T in einer statischen Methode ein nicht statische Aufrufen Allgemeine Java-Themen 5
D Statische, generische Methode will nicht. Allgemeine Java-Themen 2
H Zugriff auf statische Methode durch mehrere User Allgemeine Java-Themen 19
S Auf statische Funktionen mit Java Reflections zugreifen Allgemeine Java-Themen 3

Ähnliche Java Themen

Neue Themen


Oben