# Design Pattern gesucht!



## Gelöschtes Mitglied 5909 (18. Jul 2011)

Da ich einen kleinen Knoten im Kopf habe frage ich hier mal nach 

Und zwar habe ich zwei recht ähnliche Objekte, die einen Status haben.
Ein persistentes Objekt und ein Transferobjekt.


```
class Persistent {
  String state;
  //...
}

enum state {
   NEW, EDIT, PRODUCTION
}

class Transfer {
  State state;
  //...
}
```

Das Transferobjekt kommt über einen REST Service rein, 
das Persistent Objekt ist das ggf. vorhandene pendent in der DB.

Nun möchte ich vor und nach jedem Statuswechsel bestimmte aktionen auslösen.
Als erstes habe ich an das State Pattern gedacht, aber ich habe kein verhalten,
dass den Status verändert, sondern ich habe einen Status wechsel,
dass ein verhalten auslöst. Also genau umgekehrt.

Folgendes möchte ich erreichen:
Bevor das Transferobjekt gespeichert wird (und in ein Persistent Objekt gemapped wird),
will ich validierungen durchführen. Danach möchte ich z.B. eine Email verschicken.

Was ich nicht machen kann:
- Das Transferobjekt verändern (interfaces implementieren etc.)
- Die Transferobjekte sind generiert und werden immer neu generiert
- Im Persistent Objekt kann ich nicht das State enum verwenden

Was ich machen will:
- StateListener registrieren (aufruf vor und nach dem übergang)
- Den vorgang ggf. abbrechen (validierung fehlgeschlagen,...)
- das ganze erweiterbar halten (neue states und transitions)

Was ich vermeiden will:

```
if (oldstate == ... && newstate == ...)
else if (oldstate == ... && newstate == ...)
else if (oldstate == ... && newstate == ...)
else if (oldstate == ... && newstate == ...)
else if (oldstate == ... && newstate == ...)
else if (oldstate == ... && newstate == ...)
```

Was ich nicht nutzen will:
- BPM Engine oder vergleichbar, da zu komplex, kostet zu viel performance 
	(da ich primär für die Daten keine SQL DB verwende)

Irgendjemand eine brauchbare Idee?


----------



## maki (18. Jul 2011)

Strategy pattern vielleicht?


----------



## MrWhite (18. Jul 2011)

maki hat gesagt.:


> Strategy pattern vielleicht?



Kam mir auch als erstes in den Sinn. Gerade in Java sind die Enums maechtig. Da kannst du die zugehoerigen Strategien (oder deren Typen) direkt in der Enum mit dem State assozieren. Vielleicht pro State eine  PreState- und eine PostStateStrategy?


----------



## Landei (18. Jul 2011)

Ich würde aus altem und neuem State einen Schlüssel basteln, und die zugehörige Aktion in einer Map ablegen, etwa:


```
Map<String, Runnable> map = new HashMap<String, Runnable>();
map.add("" + NEW + EDIT, new Runnable(){public void run(){ action1(); }});
map.add("" + NEW + PRODUCTION, new Runnable(){public void run(){ action2(); }});
...

Runnable r = map.get("" + oldstate + newstate);
if (r != null) r.run();
```

Statt Runnable könnte man natürlich auch einen spezialisierten funktionsartigen Wrapper benutzen, der z.B. passende Argumente akzeptiert.


----------



## Gelöschtes Mitglied 5909 (18. Jul 2011)

Das sind schonmal sehr gute Denkanstöße, Danke!

Was haltet Ihr davon, wenn ich Landeis vorschlag mit dem Stragety Pattern kombiniere, sodass sich die angewandte Strategy aus dem zusammengesetzten Key Ergibt?

// Edit:

was haltet ihr davon? Da ich aber mehrere diese Objektpärchen habe muss ich mir nurnoch überlegen wie ich das möglichst generisch lösen kann, da ich die Transferobjekte keiner interfaces implementieren kann. Warscheinlich nehm ich da dann reflection.


```
class Transition {
	String oldState;
	State newState;
		
	// Transitions als Konstanten merken
	
	equals, hashcode!

}

interface TransitionContext {
	Persistent persistent;
	Transfer transfer;
}

interface TransitionListener {
	void beforeTransition(Transition, TransitionContext context);
	void afterTransition(Transition, TransitionContext context); 

}

class TransitionManager {

	Map<Transition, TransitionListener> listeners = new HashMap<Transition, TransitionListener>();

	void addTransitionListener(Transition transition, TransitionListener listener) {
		...
	}
	
	void beforeTransition(Persistent persistent, Transfer transfer) {
		TransitionContext context = createContext(persistent, transfer);
		Transition transition = getTransition(context);
		TransitionListener listener = listeners.get(transition);
		if (listener != null) {
			listener.beforeTransition(transition, context);
		}
	}

	void afterTransition(Persistent persistent, Transfer transfer) {
		TransitionContext context = createContext(persistent, transfer);
		Transition transition = getTransition(context);
		TransitionListener listener = listeners.get(transition);
		if (listener != null) {
			listener.afteTransition(transition, context);
		}
	}
	

}
```


----------

