# Großes Projekt "gut" schreiben



## beastofchaos (4. Aug 2012)

Hallo Leute,
Ich sitze zur Zeit an einem größeren Projekt - ein Grafikprogramm. In der Anwendung ist es sehr mit Paint.NET verwandt.
Ich werde zu dem Programm im Winter dieses Jahres eine BLL für meine 5.PK im Abitur einreichen (Thema: "Wie schreibe ich ein Grafikprogramm in einer dynamischen Sprache wie Java?").

Da ich auch das Programm selber zeigen werde, will ich auch das der Code schönst möglich wird. Bin im Moment bei 91 Klassen bzw. 18000 Zeilen. In diesem Thread würde ich gerne mehrere Fragen stellen. Im Moment hab ich erstmal 2:

*1. Frage - Internationalization:*
Für die I18N füge ich jedem Objekt, bei dem das nötig ist eine "refresh()"-Methode hinzu, in der ich alle Titel und Beschreibung aktualisiere, um eine neue Sprache zu übernehmen. Dafür rufe ich in meiner Main-Klasse, welches die wichtigsten Panels und andere Objekte enthält, die "refresh()"-Methode auf. Diese ruft unter anderem dann von den Unter-panels die "refresh()"-Methoden auf. Dafür muss ich halt alle Objekte darüber in gewisser Weise verketten. Jetzt dachte ich, es wäre schöner, ein Interface "Refreshable" zu erzeugen und dann jedem benötigten Objekt hinzufügen. Diese Objekte füge ich dann alle einem "Refreshable"-Array hinzu, wo dann alle "refresh()"-Methoden aufgerufen werden. Das wäre meine erste Idee. Aber jetzt ist mir auch eingefallen, man könnte ja von dem Main-Objekt alle Eigenschaften bzw Unter-Panels dynamisch laden und prüfen, ob es sich dabei um Refreshable-Objekte handelt, um bei denen das selbe dann durchzuführen. Welche Idee findet ihr besser und zur zweiten: Wie lade ich denn Eigenschaften eines Objekts dynamisch zur Laufzeit?

*2. Frage - Singletons:*
Da ich bei vielen Methoden mal schnell auf ein anderes Objekt zu greifen muss, hab ich bisher einfach jedem Objekt eine Referenz auf das Main-Objekt gegeben, von wo aus man alle Objekte erreichen kann. Bloß ist es sicher nicht schön, in jeder Klasse so eine extra Referenz liegen zu haben. Also muss ich zu Singletons greifen. Jetzt ist die Frage, wie ich das ausreizen kann. Soll jede Klasse für ein "einzigartiges" Objekt ein Singleton haben oder soll es nur ein paar sein, von denen ich immer noch direkt auf Unterobjekte zugreifen kann, anstatt bei denen wiederum ein Singleton aufzubauen. Sprich entweder :

```
Main.getSingleton().center.setTool(Design.Rectangle);
```
oder :

```
Center.getSingleton().setTool(Design.Rectangle);
```

Es ist doch sicher nicht toll, überall immer Singleton zu benutzen, oder schon?


Gruß, Thomas


----------



## Landei (4. Aug 2012)

1) Ich würde entschieden davon abraten, die Sprache zur Laufzeit zu ändern. Die zusätzliche Komplexität steht in keinem Verhältnis zum Nutzen. Oder wechselst du ständig zwischen Deutsch und Englisch? 

Also Sprache konfigurierbar machen und einen Hinweis anzeigen, dass die Änderung erst beim nächsten Start zu sehen ist. Auch viele kommerzielle Programme machen das so.

2) Singletons sind böse, das ist im Forum schon lang und breit diskutiert worden. Entweder Factories oder abstrakte Factories nehmen, oder Dependency Injection (Spring, wenn du davon auch andere Dienste gebrauchen kannst, Guice für "stand-alone")

Anmerkung: Java ist nach allgemein üblicher Definition keine "dynamische" Sprache (das wären z.B. Ruby, Groovy oder JavaScript), sondern eine statische, da sie ein statisches Typsystem besitzt (eine Variable besitzt bereits zur Compile-Zeit einen festen Typ, der Compiler überprüft die korrekte Typisierung, der Laufzeit-Typ kann nur ein Untertyp des Compile-Zeit-Typs sein).


----------



## Spacerat (4. Aug 2012)

@Landei: "Singletons sind böse"; Das ist schon wieder so eine voreingenommene allgemein Aussage.

@TO: Aber eigentlich hat Landei damit völlig recht. Singletons sind relativ schwerfällig wieder aufzulösen, wenn man merkt, dass sich dieses Pattern doch als Designfehler erweist und das tut es in 97% aller Fälle. Das bedeutet, man muss vorher 'ne ganze Menge anderer Ideen verworfen haben (z.B. Landeis Beispiele Factory usw.) bevor man exessiv Singletons implementiert. Anzunehmen, man könnte diese Fehler irgendwann mit z.B. Reflections oder ähnlichem wieder ausbügeln, wäre fatal.


> Wenn du dich mit dem Teufel einlässt, ändert du nicht den Teufel, sondern der Teufel ändert dich.


Wie auch immer... "gut schreiben" kann man eigentlich nur Dinge die mein Konto betreffen.


> Du musst dich nicht bedanken, du musst mich bezahlen. :lol:


----------



## beastofchaos (4. Aug 2012)

Hab mich dazu jetzt ein bisschen informiert, aber mir will der direkte Vorteil nicht klar werden. Ich benutzte den Konstruktor über eine create-Methode, aber wofür?

Was ich mir angeschaut habe

Wikipedia - Fabrikmethode

theserverside.de - Factory Method Pattern 


Vll. würd mir ein besseres Tutorial oder eine schnellere Erklärung helfen 

Gruß, Thomas

PS: Das mit der I18N ist geklärt. Dankeschön!


----------



## maki (4. Aug 2012)

Sieh dir doch mal Google Guice an falls du dich für DI interessierst


----------



## beastofchaos (4. Aug 2012)

Das 1 Stunden Video da? :S


----------



## maki (4. Aug 2012)

Ja, zum Beispiel, und die Doku lesen.

Wirst insgesamt mehr als 10 Minuten investieren müssen wenn du was darüber lernen willst wie man "Große Projekte gut schreibt"


----------



## Landei (4. Aug 2012)

Spacerat hat gesagt.:


> @Landei: "Singletons sind böse"; Das ist schon wieder so eine voreingenommene allgemein Aussage.



Es gibt immer Ausnahmen, aber das sollte einen nicht davon abhalten, Daumenregeln kurz und knackig zu formulieren ;-)


----------



## Ullenboom (4. Aug 2012)

Ein Singleton ist überhaupt nicht schlecht! Es gibt in jeder Anwendung Dinge, dir nur einmal da sind. Und das heißt Singleton. Mehr nicht. Es ist ein Design-Pattern kein Implementierungs-Pattern. Und bei der Umsetzung gibt es gute und schlechte Lösungen. Es ist super, wenn das Singleton vom Framework kommt, daher ist eine Architektur mit IoC zu empfehlen, also etwa mit Guice oder Weld oder gleich ganz groß mit Java EE Container, gerne auch Web-Profil. Das baut dir das Objekt einmal auf uns spritzt an die die Stellen, die es brauchen.

Was die Sprache angeht: Es gibt in Anwendungen immer ein Context-Objekt, das so etwas wie den  aktuellen Benutzer, Sprache und ähnliches referenziert. Sich von dort die aktuelle Locale zu holen und dann zum Beispiel bei String.format( context.getLocale(), ... )  zu übergeben ist kein Problem. Die Locale sollte IMO immer klar sein, wie das Encoding und selten so was "Default von der Plattform".


----------



## Spacerat (4. Aug 2012)

Was bitte sind das denn für dusselige Erklärungen für Factorys (okay, die 2. ist zwar relativ passend, aber Wikipedia...:shock?
Kurz gesagt, ein simples "createNewInstance()" ist zu wenig, hääte zuviel von Reflections und wäre damit etwas, was man nicht auch per Konstruktor in den konkreten Klassen hinbekommen würde.
Zu dem "createNewInstance()" gehört mindestens noch ein Parameter oder eine generische Typisierung, was, bzw. welches abstrakte Objekt instanziert werden soll. Das ja der gravierende Unterschied zum Singleton - man bekommt immer eine neue Instanz eines Objekts, statt immer die selbe. Als Singleton-Ersatz ist's in soweit also weniger geeignet, aber Singletons sind auch selten passend. Neben Factorys eignen sich evtl. dann auch noch statische Utility Klassen und Methoden (z.B. wie java.lang.Math).
Mal der Versuch einer Erklärung mit passendem Beispiel einer Paint-Anwendung.
Ein Paint-Context hat genau einen Originator - der Punkt, von dem seine Ausdehnungen in festgelegten Einheiten gezählt werden). Wollte man nur einen Paint-Context bearbeiten, wären beides (Context und Origin) Kandidaten für ein Singleton. Diese Design-Entscheidung wäre aber nun dahingehend fatal, wenn man sich in zukünftigen Versionen dazu entscheidet, doch mehrere Contexte gleichzeitig bearbeiten zu wollen. Mit einem "Context.getInstance()" käme man nun nicht mehr sehr weit, aber mit 'ner Factory- und und zwei Utility-Methoden (createContext, get- und setActiveContext) in der Hauptanwendung (Main) dagegen schon. Natürlich bräuchten mehrere Contexte auch verschiedene Originatoren, somit wären beide Singletons hinfällig.
[EDIT]





Landei hat gesagt.:


> Es gibt immer Ausnahmen, aber das sollte einen nicht davon abhalten, Daumenregeln kurz und knackig zu formulieren ;-)


Klar... einverstanden... und ich erklär mir hier 'nen Wolf... :lol:[/EDIT]


----------



## beastofchaos (4. Aug 2012)

Naja ich steh mächtig unter Druck, weil das Programm für meine akribischen Lehrer zu wenig Dokumentation enthält, und ich auch bald mit den 20 Seiten BLL anfangen muss. Das Video muss warten - Ich mach jetzt einfach ein Singleton für Main und streich alle Referenzen dazu. Wenn ich mal Zeit haben SOLLTE, werde ich mich gerne ein paar Stunden/ Tage mit dem Thema beschäftigen und Guice ausprobieren, aber da mir das als auch Factory nicht ganz sinnig bisher erscheint (die Erklärung ist mir zu ... komisch ), muss ich wohl weiterhin so arbeiten.

Wenn ich wieder andere Fragen habe sollte, folgen die hier noch. Bis dann 

Thomas


----------



## tfa (4. Aug 2012)

Ullenboom hat gesagt.:


> Ein Singleton ist überhaupt nicht schlecht! Es gibt in jeder Anwendung Dinge, dir nur einmal da sind. Und das heißt Singleton. Mehr nicht. Es ist ein Design-Pattern kein Implementierungs-Pattern.


Kommt drauf an, was man unter Singleton versteht. Wenn man sich den Beispielcode des TS ansieht, ist wohl von einem GoF-Singleton die Rede, und das ist nunmal fast immer schlecht. (In diesem Fall hieße Singleton nicht "Dinge, die nur einmal da sind", sondern "Dinge, die es nur einmal geben darf"!).
Ein Singleton im Sinne von Singleton-Scope in DI ist natürlich vorzuziehen.


----------



## Spacerat (4. Aug 2012)

@TFA: Seit wann sind Design-Patterns Ansichtssache? Das Singletonpattern definiert ein Pattern, das genau nur eine Instanz einer Klasse zulässt, mehr gibt es da nicht zu verstehen, nur verwechseln kann man viel. Von daher ist's egal, ob ein Injektor oder die Klasse selbst das Singleton instanziert, obwohl ein Injektor niemals echte Singletons produzieren kann, weil es dazu an den privaten Konstruktor der Klasse müsste. Noch mal zur Erinnerung:

```
class Singleton {
  private static final Singleton instance;

  static {
    synchronized(Singleton.class) {
      instance = new Singleton();
    }
  }

  private Singleton() {
  }

  public static Singleton getInstance() {
    return instance;
  }
}
```
Das ist ein Singleton, alle anderen Implementationen bzw -versuche (bis auf die Methoden des Singletons)  sind was anderes.
[EDIT]Okay, man könnte "getInstance()" noch synchronized machen und nach einer Abfrage gegen null es auch dort instanzieren... aber das ist weniger sicher, wenn mehrere Classloader versuchen die Klasse zu laden.[/EDIT]


----------



## ...ButAlive (4. Aug 2012)

Meiner Meinung nach ist das Singleton-Pattern, das Pattern das mit am Meisten Vorsicht zu genießen ist. In machen Fällen hat es sicherlich seine Berechtigung, und zwar dann wenn es nur genau eine Instanz geben *darf*, zum Beispiel darf nur genau ein Serversocket auf einem Port laufen.

Das Singleton-Pattern sollte man nicht verwenden, wenn man aus Bequemlichkeit nur genau eine Instanz haben will und dann von allen möglichen Stellen darauf zu referenzieren. Denn:

1.) Der Code ist undurchsichtig. Eigentlich sollte man versuchen Variablen den kleinst möglichen Scope zu geben. Singletons haben den größt möglichen, und zwar global.

2.) Wenn man doch mal 2 Instanzen braucht, ziehen sich die Änderungen durch das gesamte Projekt. Da man bei Softwareprojekten selten gut abschätzen kann, was in Zukunft kommt, sollte man sich durch Bequemlichkeit nichts verbauen.

Mit der Meinung stehe ich nicht ganz alleine da, selbst Erich Gamma hat in einem Interview auf die Frage, welches Pattern er entfernen würde geantwortet:



> When discussing which patterns to drop, we found that we still love them all. (Not really—I'm in favor of dropping Singleton. Its use is almost always a design smell.)



Quelle

@TO Wenn es ein Schulprojekt ist, dass nach der Benotung in der Schublade verschwindet, kannst du ruhig Singletons nehmen, solange es funktioniert ist es ok, Wartbarkeit wird dann keine Rolle spielen. Wenn du deine Frage "Großes Projekt "gut" schreiben" beantworten willst, solltest du dich doch mal mit DI beschäftigen und zum Beispiel Guice näher anschauen.


----------



## tfa (4. Aug 2012)

Spacerat hat gesagt.:


> Seit wann sind Design-Patterns Ansichtssache? Das Singletonpattern definiert ein Pattern, das genau nur eine Instanz einer Klasse zulässt, mehr gibt es da nicht zu verstehen, nur verwechseln kann man viel. Von daher ist's egal, ob ein Injektor oder die Klasse selbst das Singleton instanziert, obwohl ein Injektor niemals echte Singletons produzieren kann, weil es dazu an den privaten Konstruktor der Klasse müsste. Noch mal zur Erinnerung:



Dann hast du den Unterschied nicht verstanden zwischen dem Entwurfsmuster _Singleton_ gemäß GoF, und dem, was DI-Frameworks wie Guice oder Spring als Singleton bezeichnen (ich vermute, dass Ullenboom das mit "Singleton, das vom Framework kommt" meinte). Das ist ein sehr großer  Unterschied und vielleicht am Anfang etwas verwirrend. Wenn man sich aber ein wenig damit auseinander setzt, ist es gar nicht so schwer.



> [...]Das ist ein Singleton


... wie es die meisten Anfänger falsch verwenden. Richtig. Für Singletons in der DI-Framework-Welt reicht eine 
	
	
	
	





```
@Autowired
```
 bzw. [c]@Inject[/c] oder [c]@Singleton[/c] Annotation.


----------



## Spacerat (4. Aug 2012)

tfa hat gesagt.:


> Für Singletons in der DI-Framework-Welt reicht eine
> 
> 
> 
> ...


Wie gesagt, das Design-Pattern Singleton ist keine Auslegungssache. Wie irgendwelche Frameworks ihre Klassen auch nennen oder implementieren oder instanzieren mögen, das Design-Pattern bleibt davon unberührt. Das meinte ich mit "verwechseln kann man viel". Und man ist nicht gleich ein Anfänger, nur weil man diese dubiosen Frameworks nicht verwendet.


----------



## tfa (5. Aug 2012)

Spacerat hat gesagt.:


> Und man ist nicht gleich ein Anfänger, nur weil man diese dubiosen Frameworks nicht verwendet.


Sicher. Trotzdem sollte man (ob nun Anfänger oder nicht) offen für Neues sein und seinen Horizont erweitern, eher man etwa behauptet, ein Singleton sei genau _das_  und nichts anderes.


----------



## Landei (5. Aug 2012)

Spacerat hat gesagt.:


> ```
> class Singleton {
> private static final Singleton instance;
> 
> ...



I beg to differ. Die "empfohlene" Implementierung sieht inzwischen ungefähr so aus:


```
public enum Singleton {
   INSTANCE;
   //put something useful here
}
```

Das ist nicht nur kürzer, man vermeidet damit auch unschöne Überraschungen (etwa bei Serialisierung).  

By the way: Für Utility-Klassen (die also nur statische Methoden und Felder enthalten, aber keine Instanzen haben), bin ich inzwischen übergegangen zu:


```
public enum Utility {
   ;
   //put something useful here
}
```


----------



## Spacerat (5. Aug 2012)

Landei hat gesagt.:


> I beg to differ. Die "empfohlene" Implementierung sieht inzwischen ungefähr so aus:
> 
> 
> ```
> ...


It's only a pseudo too.  Das ist ein Kompromiss, sich vorläufig für Singleton entscheiden zu können. Wenn man merkt, dass es eine Fehlentscheidung war, entfällt der Änderungsaufwand im Projekt, weil man aus INSTANCE2 ganz leicht 'ne Factory machen kann (um einiges leichter, als beim echten Singleton).

```
public enum Singleton implements FactoryProduct {
   INSTANCE,
   DEFAULT;
   // implements the original or
   // delegates stuff to a new ExSingleton implementation
   public static FactoryProduct newInstance(Class<? extends FactoryProduct> whatever) {
      // do the production things.
   }
}
```
Das sieht zwar jetzt dussellig aus, aber was soll's, es bezeugt ja die einst dusselige Entscheidung Singleton verwenden zu wollen. Das interface FactoryProduct bietet nun alle (brauchbaren) Methoden des Ex-Singletons an, so bleibt das neue Design abwärtskompatibel. Überall, wo Singleton verwendet wurde, kann man nun FactoryProduct einsetzen (evtl. per Refactoring). Das ist halt 'ne Implementationsmöglichkeit wie bei DI-Frameworks.
Sicher bleibt es einfacher, ein paar Annotationen auszutauschen, um Klassen einen Status zuzuweisen, man darf dabei aber nicht vergessen, wie die einzelnen Patterns funktionieren, bevor man evtl. behauptet, andere lägen mit ihren Behauptungen falsch.
BTW.: Singletons serialisieren? Wozu? Sind doch überall dort, wo das jeweilige API verwendet wird gleich. Sollten sie jedenfalls. Deswegen ist Serializable bei Singletons auch fehl am Platz.
BTW2.: Nö, Landei... Für Utilityzeugs, sehe ich da keinerlei Nutzen, sorry.


----------



## FArt (6. Aug 2012)

Spacerat hat gesagt.:


> @TFA: Seit wann sind Design-Patterns Ansichtssache? Das Singletonpattern definiert ein Pattern, das genau nur eine Instanz einer Klasse zulässt, mehr gibt es da nicht zu verstehen, nur verwechseln kann man viel. Von daher ist's egal, ob ein Injektor oder die Klasse selbst das Singleton instanziert, obwohl ein Injektor niemals echte Singletons produzieren kann, weil es dazu an den privaten Konstruktor der Klasse müsste. Noch mal zur Erinnerung:
> 
> ```
> class Singleton {
> ...



Eigentlich wollte ich diese mal zur Singleton-Diskussion den Mund halten, aber das hier ist m.E. eine Antwort wert.

Der Code könnte viel einfacher aussehen:

```
class Singleton {
  private static final Singleton instance = new Singleton();

  private Singleton() {
  }

  public static Singleton getInstance() {
    return instance;
  }
}
```
Der static initializer ist völlig sinnlos. Statische Felder (und static initializer) sind sowieso threadsafe, somit kann auch die Synchronisation wegfallen.

Und getInstance() muss somit natürlich auch nicht synchronisiert werden.
Und warum soll das weniger sicher sein, wenn mehrere Classloader versuchen die Klasse zu laden? Jeder Classloader kann sich dieses Klasse problemlos laden und erstellt natürlich somit sein eigenes "Singleton".



Spacerat hat gesagt.:


> Singletons serialisieren? Wozu? Sind doch überall dort, wo das jeweilige API verwendet wird gleich. Sollten sie jedenfalls. Deswegen ist Serializable bei Singletons auch fehl am Platz.


Singletons können Status halten. Sie können in einer VM mehrfach existieren. Bei Remotekommunikation können sie auch in mehreren VMs existieren. Sie sind also nicht überall gleich, wo die passende API verwendet wird.
Und es kann auch sinnvoll sein, ein Singleton (mit Status) zu serialisieren (z.B. zur Kurzzeitpersistierung).


----------



## FArt (6. Aug 2012)

Landei hat gesagt.:


> By the way: Für Utility-Klassen (die also nur statische Methoden und Felder enthalten, aber keine Instanzen haben), bin ich inzwischen übergegangen zu:
> 
> 
> ```
> ...


Kannst du den Grund erläutern? Ich sehe keinen Untesrchied zu einer Klasse mit statischen Methoden und Feldern, außer dass du ein Enum verwendest, welches keines ist.


----------



## Landei (6. Aug 2012)

Man spart sich den privaten Konstruktor, der eine Instantiierung verhindert (was sowie schon ein wenig Gaga ist: eine Konstruktor schreiben, damit ihn niemand aufrufen kann). Ein Aufzählungstyp ohne Elemente drückt diese Intention meiner Meinung nach eleganter aus. Dass das dann kein "echter" Enum-Typ ist, würde ich nicht sagen: Das Konzept der leeren Menge zieht sich schließlich quer durch die ganze Informatik.

Aber ich denke, dass man hier getrost von einer Frage des persönlichen Geschmacks ausgehen kann, beide Varianten leisten das Gewünschte.


----------



## Mujahiddin (6. Aug 2012)

Landei hat gesagt.:


> Man spart sich den privaten Konstruktor, der eine Instantiierung verhindert (was sowie schon ein wenig Gaga ist: eine Konstruktor schreiben, damit ihn niemand aufrufen kann). Ein Aufzählungstyp ohne Elemente drückt diese Intention meiner Meinung nach eleganter aus. Dass das dann kein "echter" Enum-Typ ist, würde ich nicht sagen: Das Konzept der leeren Menge zieht sich schließlich quer durch die ganze Informatik.
> 
> Aber ich denke, dass man hier getrost von einer Frage des persönlichen Geschmacks ausgehen kann, beide Varianten leisten das Gewünschte.



Deine Argumentationskünste muss man haben! Du hast mich soeben überzeugt.

P.S. trotzdem finde ich persönlich abstrakte Klassen mit privatem Konstruktor schöner - ich finde das rote E beim Eclipse Autofiller, wenn du nach der Klasse suchst, ziemlich unansehnlich und irreführend. Conventions halt - die Ketten der Programmiersprache.


----------

