Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

State pattern pro und contra?

15 views
Skip to first unread message

Marcus Woletz

unread,
Dec 25, 2009, 3:43:28 PM12/25/09
to
Hallo Leute,

eine kurze Frage: verwendet ihr immer, wo möglich, das State pattern?
Ich wollte mich streng an die pattern halten und setzte deshalb in einem
Grafikeditor das State pattern um. Das war mir irgend wann allerdings zu
stressig, da in meinem Programm zig Objekttypen mit wiederum mehreren
möglichen Zuständen existieren. Durch das State pattern wird IMO ein
Programm durch eine große Anzahl zusätzlicher Klassen aufgebläht, und im
Gegensatz zur Alternativen if-Anweisung und Kodierung der Zustände als
Ganzzahl scheint mir das state pattern auch deutlich unübersichtlicher.
Ich würde sogar so weit gehen und das state pattern als anti pattern
einordnen. Es ist einfach unhandlich. Ich würde das state pattern ja
gerne grundsätzlich einsetzen, aber mir gefällt's einfach nicht.

Wie ist eure Meinung dazu: Immer State pattern verwenden, um streng nach
Regeln zu arbeiten und zeigen, dass man "in" ist, oder bei Bedarf auch
die gute alte Variante (wie beschrieben) verwenden?

ciao

Marcus

Karl Heinz

unread,
Dec 25, 2009, 5:46:47 PM12/25/09
to
Marcus Woletz schrieb:

> eine kurze Frage: verwendet ihr immer, wo m�glich, das State pattern?

Das h�ngt davon ab, was man als 'm�glich' ansieht. Z.B. k�nntest
du in einer Klasse Person den Zustand isSonntagsKind definieren und
hast dann durchaus die M�glichkeit, das durch ein state-Objekt zu tun.

> Ich wollte mich streng an die pattern halten und setzte deshalb in einem
> Grafikeditor das State pattern um.

Nenn einfach bitte mal Beispiele f�r verwendete (oder als solche
gedachte) states in den relevanten Klassen.

Wenn man solche Eigenschaften als ('echte') states sieht, die eine
relevante Auswirkung auf das Verhalten von Objekten in einer Form
haben, da� sie die (evtl. zus�tzlichen) Kosten f�r die Anwendung
von state-Objekten wieder einbringen, z.B. durch mehr Klarheit,
bessere Wartbarkeit, oder Gewinn eines schnelleren Algorithmus,
u.a., d�rfte man eher richtig liegen.

Also, z.B. dann, wenn sich das Verhalten der stateful objects
durch Polyphormismus filtern l��t, etwa, indem alle Schreibzugriffe
auf read-only-objekte generell vereitelt werden, weil entsprechende
Methoden gar nicht erst zur Verf�gung stehen, oder wenn z.B.
ein Streamreader gleich beim Einlesen der Zeichen eine Reihe von
states, die vielleicht noch eng zusammenh�ngen, "mitrechnet"
und das nicht erst in sp�teren Schleifen zeitraubend erledigt.

Marcus Woletz

unread,
Dec 26, 2009, 10:28:59 AM12/26/09
to
Hallo Karl Heinz,

danke für Deine Antwort!


Karl Heinz schrieb:
> Marcus Woletz schrieb:
>
>> eine kurze Frage: verwendet ihr immer, wo möglich, das State pattern?
>
> Das hängt davon ab, was man als 'möglich' ansieht. Z.B. könntest

> du in einer Klasse Person den Zustand isSonntagsKind definieren und

> hast dann durchaus die Möglichkeit, das durch ein state-Objekt zu tun.

>
>> Ich wollte mich streng an die pattern halten und setzte deshalb in einem
>> Grafikeditor das State pattern um.
>

> Nenn einfach bitte mal Beispiele für verwendete (oder als solche

> gedachte) states in den relevanten Klassen.

einfachtes Beispiel: zeichnen einer Linie, hier etwas vereinfacht
dargestellt.

1.) Im Objektmenü des Programms "Linie zeichnen" wählen. Das Programm
erstellt eine Instanz der Klasse "Linie", das sich dann im Zustand
"erzeugt" befindet. Diese Instanz wird als "editiertes Objekt" in der
"DrawingPane" gespeichert. Von nun an werden alle Eingabeoperationen an
dieses "editierte Objekt" weitergeleitet.

2.) Der Anwender bewegt nun den Bildschirmzeiger zur gewünschten
Position des Startpunktes der Linie.

3.) Der Anwender betätigt die linke Maustaste, wodurch der Startpunkt
festgelegt ist. Das Linienobjekt wechselt vom Zustand "erzeugt" in den
Zustand "erster Startpunkt festgelegt".

4.) Der Anwender bewegt den Bildschirmzeiger zur gewünschten Position
des Endpunktes der Linie.

5.) Der Anwender betätigt abermals die linke Maustaste und legt dadurch
den Endpunkt der Linie fest. Das Linienobjekt wechselt in den Zustand
"fertiggestellt" und wird automatisch in die Liste der bereits
gezeichnteten Liste aufgenommen.

6.) Betätigt der Anwender nach Punkt 3.), also entweder in 4.) oder 5.)
die ESC-Taste, wird der festgelegte Startpunkt verworfen und das Objekt
wechselt wieder in den Zustand "erzeugt".


Das ganze kann nun dadurch umgesetzt werden, dass im Objektin einem int
eine Zustandsnummer gespeichert wird. In den einzelnen Eingabemethode
(mousePressed, mouseMoved etc.) wird dann abhängig vom Zustand die
jeweilige Aktion ausgeführt.

Wird nun alles mit dem state pattern umgesetzt, dann muss für jeden
möglichen Zustand der verschiedenen Objekttypen (Linie, Polylinie,
Polygonlinie, Kreis, Text. etc. pp) eine Klasse erstellt werden. Und da
bin ich der Meinung, dass durch die vielen Klassen ein wenig der
Überblick leidet.

Dumm ist halt, dass, wenn ich mich einmal auf die entsprechende Variante
(state pattern oder "klassisch") fesgegelegt habe, das nur mit einigem
Aufwand in die andere Variante überführt werden kann.


Im extremfall könnte man z.B. einen Lexer oder Parser mit Hilfe des
state Pattern implementieren. wenn man allerdings bedenkt, dass ein
derartiger Parser schnell einige hundert Zustände haben kann (sofern man
die state machine nicht mit einer Zustandstabelle umsetzt), ist wohl
auch dort das state pattern der Übersichtlichkeit eher nicht dienlich.

Ein anderes Beispiel ist Dein Sonntagskind. Da würde man wohl ebenfalls
eher nicht auf die Idee kommen, dafür extra das state pattern zu bemühen.

[...]

ciao

Marcus

Karl Heinz

unread,
Dec 26, 2009, 11:29:35 AM12/26/09
to
Marcus Woletz schrieb:
> Karl Heinz schrieb:

>> Nenn einfach bitte mal Beispiele f�r verwendete (oder als solche

>> gedachte) states in den relevanten Klassen.
>
> einfachtes Beispiel: zeichnen einer Linie, hier etwas vereinfacht
> dargestellt.
>

> 1.) Im Objektmen� des Programms "Linie zeichnen" w�hlen. Das Programm


> erstellt eine Instanz der Klasse "Linie", das sich dann im Zustand
> "erzeugt" befindet. Diese Instanz wird als "editiertes Objekt" in der
> "DrawingPane" gespeichert. Von nun an werden alle Eingabeoperationen an
> dieses "editierte Objekt" weitergeleitet.

Ja, �bliche Entkopplung von Objekt und Realisierung, z.B. auf
einem spezifischen Drucker oder Plotter.

> 2.) Der Anwender bewegt nun den Bildschirmzeiger zur gew�nschten


> Position des Startpunktes der Linie.

Das hat aber mit obigem zun�chst nicht vile zu tun, sondern betrifft
ein Detail der Erstellung.

> 3.) Der Anwender bet�tigt die linke Maustaste, wodurch der Startpunkt


> festgelegt ist. Das Linienobjekt wechselt vom Zustand "erzeugt" in den
> Zustand "erster Startpunkt festgelegt".

Ja.

> 4.) Der Anwender bewegt den Bildschirmzeiger zur gew�nschten Position
> des Endpunktes der Linie.
>
> 5.) Der Anwender bet�tigt abermals die linke Maustaste und legt dadurch


> den Endpunkt der Linie fest. Das Linienobjekt wechselt in den Zustand
> "fertiggestellt" und wird automatisch in die Liste der bereits
> gezeichnteten Liste aufgenommen.

Aha, das w�re dann hier ein Zustand, der einen Undo-Mechanismus
(oder -Buffer) einbringt. Dieser kann dann mal "beliebig" komplex werden.

> 6.) Bet�tigt der Anwender nach Punkt 3.), also entweder in 4.) oder 5.)


> die ESC-Taste, wird der festgelegte Startpunkt verworfen und das Objekt
> wechselt wieder in den Zustand "erzeugt".

Oder, man k�nnte auch, je nach Objekt, nur die letzte Aktion, z.B.
das abschlie�ende Verbinden eines Polygonzuges, verwerfen, dann
jeden vorigen Punkt, in Undo-Manier. Daf�r b�te sich deshalb ein
state-Objekt an, weil es die grundlegende Wirkungsweise der
Graphik vom Undo-Mechanismus trennt, der als state-machine
gesondert abschaltbar, als ganzes austauschbar oder beliebig
erweiterbar gestaltet werden k�nnte, weil man ihn in Objekten
h�lt, deren Methoden man beliebig zuschalten oder abschalten
kann, ohne einen einzigen if-spaghetti in den "Urcode" einzuf�gen,
usw, usf...



> Das ganze kann nun dadurch umgesetzt werden, dass im Objektin einem int
> eine Zustandsnummer gespeichert wird. In den einzelnen Eingabemethode

> (mousePressed, mouseMoved etc.) wird dann abh�ngig vom Zustand die
> jeweilige Aktion ausgef�hrt.

Ja.

> Wird nun alles mit dem state pattern umgesetzt, dann muss f�r jeden
> m�glichen Zustand der verschiedenen Objekttypen (Linie, Polylinie,


> Polygonlinie, Kreis, Text. etc. pp) eine Klasse erstellt werden.

Oh! Geht das nicht anders?

> Und da
> bin ich der Meinung, dass durch die vielen Klassen ein wenig der

> �berblick leidet.

Du kannst den ganzen komplexen Editor auf beliebige Weise mit
Status-Mechanismusmen versehen (einem oder mehreren) und dabei
die ganze Welt des Polymorphismus und der Dekoration einsetzen.

> Dumm ist halt, dass, wenn ich mich einmal auf die entsprechende Variante
> (state pattern oder "klassisch") fesgegelegt habe, das nur mit einigem

> Aufwand in die andere Variante �berf�hrt werden kann.

Versuch halt beides zu verbinden, d.h. die Graphikobjekte in jedem
Fall vom Transitionsmechanismus, der zu iher Entstehung f�hrt, zu
entkoppeln (wenigstens formal in der Weise, da� du den status in
einem Objekt kapselst).

> Im extremfall k�nnte man z.B. einen Lexer oder Parser mit Hilfe des


> state Pattern implementieren. wenn man allerdings bedenkt, dass ein

> derartiger Parser schnell einige hundert Zust�nde haben kann (sofern man


> die state machine nicht mit einer Zustandstabelle umsetzt), ist wohl

> auch dort das state pattern der �bersichtlichkeit eher nicht dienlich.
>
> Ein anderes Beispiel ist Dein Sonntagskind. Da w�rde man wohl ebenfalls
> eher nicht auf die Idee kommen, daf�r extra das state pattern zu bem�hen.

So ist das aber nicht "gemeint".

In deinem Beispiel h�ngt das ganze ja von deiner Objekthierarchie ab.

Nehmen wir mal an du willst ein persistentes Endergebnis vom Typ
Graphik, dann k�nnte dieses eine Collection aus vielen anderen
Objekten vom Interface-Typ Primitive, wie Punkt, Linie, Kreis,
Polygon, mit Eigenschaften wie Farbe, ua., sein.

Nun k�nnte jede der implementierten Primitive eine Methode
GraphikStatus getStatus() haben. Dann kannst du das dazugeh�rige
Statusobjekt bereits in der Implementation der Superklasse deklarieren.

Das Interface GraphikStatus erzwingt dann z.B. wiederum alle
obligatorischen Methoden, wie z.B. rollback() f�r eine
undo-Operation, gefolgt von einem redraw() oder isComplete()
um dann zu persistieren usw. Jedes Objekt kann dann entweder
das Superobjekt zugreifen, es �berschreiben oder auch dekorieren.

In einer ersten Version kannst du auch noch "die Automatik von
aussen erledigen" indem du einfach den Zustand durch Setter-
Methoden definierst. Du hast aber bereits auch dann schon ein
entkoppeltes Objekt, das allein f�r den "oberen Zustand" da ist.

Du kannst dann zun�chst in deiner Programmlogik dieses Objekt
wie gew�hnlich beeinflussen, z.B. durch "setComplete(true)",
und es "pollen", z.B. mit "if (isComplete() save())".

Allerdings kannst du dann sp�ter wahlweise mehr und mehr auf
"Automatik" �bergehen, oder eben auch nicht.

Marcus Woletz

unread,
Dec 26, 2009, 1:55:11 PM12/26/09
to
Hallo Karl Heinz,

vielen Dank für Deine ausführliche Antwort.

Karl Heinz schrieb:

[...]

>> 2.) Der Anwender bewegt nun den Bildschirmzeiger zur gewünschten


>> Position des Startpunktes der Linie.
>

> Das hat aber mit obigem zunächst nicht vile zu tun, sondern betrifft
> ein Detail der Erstellung.

Ja. Ich habe das nur geschrieben, damit der Mechanismus der
Objekterstellung klar ist.

[...]

>> Das ganze kann nun dadurch umgesetzt werden, dass im Objektin einem int
>> eine Zustandsnummer gespeichert wird. In den einzelnen Eingabemethode

>> (mousePressed, mouseMoved etc.) wird dann abhängig vom Zustand die
>> jeweilige Aktion ausgeführt.
>
> Ja.
>
>> Wird nun alles mit dem state pattern umgesetzt, dann muss für jeden
>> möglichen Zustand der verschiedenen Objekttypen (Linie, Polylinie,


>> Polygonlinie, Kreis, Text. etc. pp) eine Klasse erstellt werden.
>
> Oh! Geht das nicht anders?

Naja, ich kenne das State Pattern halt so, dass für jeden möglichen
Zustand eine Klasse erstellt wird. Wie sonst sollte man das State
Pattern umsetzen?

>
>> Und da
>> bin ich der Meinung, dass durch die vielen Klassen ein wenig der

>> Überblick leidet.


>
> Du kannst den ganzen komplexen Editor auf beliebige Weise mit
> Status-Mechanismusmen versehen (einem oder mehreren) und dabei
> die ganze Welt des Polymorphismus und der Dekoration einsetzen.

Ja, aber das entspricht dann halt nicht mehr der Intention des State
Pattern.

>
>> Dumm ist halt, dass, wenn ich mich einmal auf die entsprechende Variante
>> (state pattern oder "klassisch") fesgegelegt habe, das nur mit einigem

>> Aufwand in die andere Variante überführt werden kann.


>
> Versuch halt beides zu verbinden, d.h. die Graphikobjekte in jedem

> Fall vom Transitionsmechanismus, der zu iher Entstehung führt, zu
> entkoppeln (wenigstens formal in der Weise, daß du den status in
> einem Objekt kapselst).

Also etwa ein GraphicObjectEditor, von dem dann die konkreten Editoren
abgeleitet werden?

[...]

Insgesamt war eben die Frage, ob man in diesem Fall das State Pattern
streng nach Lehrbuch implementieren sollte.


ciao

Marcus

Message has been deleted

Karl Heinz

unread,
Dec 26, 2009, 4:14:27 PM12/26/09
to
Marcus Woletz schrieb:

> Karl Heinz schrieb:

>>> 2.) Der Anwender bewegt nun den Bildschirmzeiger zur gew�nschten


>>> Position des Startpunktes der Linie.
>>

>> Das hat aber mit obigem zun�chst nicht vile zu tun, sondern betrifft

>> ein Detail der Erstellung.
>
> Ja. Ich habe das nur geschrieben, damit der Mechanismus der
> Objekterstellung klar ist.

Sorry, mein Irrtum, beim nochmal Lesen habe ich festgestellt, da�
ich davon ausgegangen war, da� du Vektorgraphiken erstellst, die
du dann in einem Ausgabeproze� renderst ;)

>>> Wird nun alles mit dem state pattern umgesetzt, dann muss f�r jeden

>>> m�glichen Zustand der verschiedenen Objekttypen (Linie, Polylinie,


>>> Polygonlinie, Kreis, Text. etc. pp) eine Klasse erstellt werden.
>>
>> Oh! Geht das nicht anders?
>

> Naja, ich kenne das State Pattern halt so, dass f�r jeden m�glichen


> Zustand eine Klasse erstellt wird.

Ja, so ist das reine Pattern: ein Automat hat Methoden, die
�ber verschiedene Objects eines state-typs (z.B. als enums)
gemappt, bzw. dekoriert werden. Z.B. k�nnte ein Stream-Reader
eine Methode automat.readChar() und die beiden states state.IN
und state.EOF (neben state.START) annehmen k�nnen, die jeweils
ihrerseits eine Methode readChar() besitzen. state wird nun als
state.START initialisiert und automat.state.readChar() liest nun
entweder ein EOF und gelangt in den finalen Zustand state.EOF oder
in den Zustand state.IN, der verlassen wird, wenn ein EOF auftaucht.

> Wie sonst sollte man das State Pattern umsetzen?

An jeder Stelle, an der du das Pattern willst, denn der Automat
besitzt ja die State-Objekte, die wahlweise Methoden dekorieren
k�nnen (nach reiner Lehre) oder sonstwie "weiteres behaviour"
implementieren.

>>> Und da
>>> bin ich der Meinung, dass durch die vielen Klassen ein wenig der

>>> �berblick leidet.


>>
>> Du kannst den ganzen komplexen Editor auf beliebige Weise mit
>> Status-Mechanismusmen versehen (einem oder mehreren) und dabei
>> die ganze Welt des Polymorphismus und der Dekoration einsetzen.
>
> Ja, aber das entspricht dann halt nicht mehr der Intention des State
> Pattern.

Das State Pattern kann als eine Art Mischform zwischen Dekoration
und Vererbung, weil man gewisserma�en die Vererbung hinter einer
Dekoration (oder Fassade) versteckt.

Du kannst ja auch hier nach reiner Lehre vorgehen. Wenn z.B.
einfach alle deine Graphikobjekte ein Super-Objekt vom Type
state enthalten (m�ssen), dann kannst du auch die state-Klasse
�berschreiben und Polymorphismus nutzen. Z.B. kannst du auch
ge�nderte State-Objects weiterreichen, in der Art wie man eben
Wrapper-Klassen einsetzt, es ist mindestens "beruhigend" zu
wissen, da� man so auch mal Ausnahmen modellkonform handlen
kann. Du kannst auch immer wahlweise entscheiden, ob du in
jedem Einzelfall state.methodeX() oder methodeX() "aufdeckst".


>>> Dumm ist halt, dass, wenn ich mich einmal auf die entsprechende Variante
>>> (state pattern oder "klassisch") fesgegelegt habe, das nur mit einigem

>>> Aufwand in die andere Variante �berf�hrt werden kann.


>>
>> Versuch halt beides zu verbinden, d.h. die Graphikobjekte in jedem

>> Fall vom Transitionsmechanismus, der zu iher Entstehung f�hrt, zu
>> entkoppeln (wenigstens formal in der Weise, da� du den status in

>> einem Objekt kapselst).
>
> Also etwa ein GraphicObjectEditor, von dem dann die konkreten Editoren
> abgeleitet werden?

Nein, der Editor ist offenbar ein Dialog, der Eingaben sammelt
und auf dem Bildschirm ausgibt (und wom�glich in eine Datenbank),
es ist dann so, da� du einen Automaten m�chtest, der selbst erkennt,
wie lange die Eingabe einem jeweils einzelnes Objekt zugeleitet
werden. Dazu brauchst du in der Tat nur ein einzelnes Flag ;)

Ich hatte da neuerdings eher an einen ganzen Undo-Mechanismus
gedacht, der z.B. die zu editierenden Objekte bis zur Fertigstellung
z.B. gestrichelt darstellt und graphische Handles (z.B. um einen
Kreis) hat, und vielleicht auch nichtmodale Dialogboxen, mit denen
man die Farbe live �ndern kann, oder das Ratio einer Ellipse, in
freier Reihenfolge also, usw.

Eine solche Kaskade von Zust�nden m�sste man sehr strukturiert
behandeln, oder man verliert schnell den �berblick...


> Insgesamt war eben die Frage, ob man in diesem Fall das State Pattern
> streng nach Lehrbuch implementieren sollte.

Auf keinen Fall daf�r jedenfalls, um "festzustellen", ob der
Editiervorgang f�r ein Graphikobjekt vollst�ndig ist, das w�re
sicherlich in der Tat Unsinn, wie du in deinem Posting ebenfalls
vermutest. Pattern zum Selbszweck bringt nat�rlich nichts.

Aber meine Idee ist ja die oben wieder angedeutete "Mischform",
man m��te dann einfach mal konkreter werden.

Wanja Gayk

unread,
Dec 26, 2009, 5:25:17 PM12/26/09
to
Marcus Woletz said...

> Das ganze kann nun dadurch umgesetzt werden, dass im Objektin einem int
> eine Zustandsnummer gespeichert wird. In den einzelnen Eingabemethode

> (mousePressed, mouseMoved etc.) wird dann abhᅵngig vom Zustand die
> jeweilige Aktion ausgefᅵhrt.
>
> Wird nun alles mit dem state pattern umgesetzt, dann muss fᅵr jeden
> mᅵglichen Zustand der verschiedenen Objekttypen (Linie, Polylinie,


> Polygonlinie, Kreis, Text. etc. pp) eine Klasse erstellt werden. Und da
> bin ich der Meinung, dass durch die vielen Klassen ein wenig der

> ᅵberblick leidet.

Die Zustᅵnde musst du nicht fᅵr jedes Objekt neu codieren, denke ich. Die
Zusᅵnde widerholen sich ja und auch die Zustandsᅵnderungen kᅵnnen sich
auch durchaus widerholen.
In Prinzip kannst du also Zustᅵnde und ᅵbergᅵnge codieren und diese fᅵr
jedes Objekt (Linie, Polylinie) anders kombinieren.

Gruᅵ,
-Wanja-

--
Klingon function calls do not have 'parameters', they have 'arguments' -
and they always win them.
[Nele Abels in dsg]

Karl Heinz

unread,
Dec 26, 2009, 5:27:44 PM12/26/09
to
superseded: habe unten noch etwas code drangehangen

Marcus Woletz schrieb:
> Karl Heinz schrieb:

>>> 2.) Der Anwender bewegt nun den Bildschirmzeiger zur gew�nschten


>>> Position des Startpunktes der Linie.
>>

>> Das hat aber mit obigem zun�chst nicht vile zu tun, sondern betrifft

>> ein Detail der Erstellung.
>
> Ja. Ich habe das nur geschrieben, damit der Mechanismus der
> Objekterstellung klar ist.

Sorry, mein Irrtum, beim nochmal Lesen habe ich festgestellt, da�

ich davon ausgegangen war, da� du Vektorgraphiken erstellst, die
du dann in einem Ausgabeproze� renderst ;)

>>> Wird nun alles mit dem state pattern umgesetzt, dann muss f�r jeden
>>> m�glichen Zustand der verschiedenen Objekttypen (Linie, Polylinie,


>>> Polygonlinie, Kreis, Text. etc. pp) eine Klasse erstellt werden.
>>
>> Oh! Geht das nicht anders?
>

> Naja, ich kenne das State Pattern halt so, dass f�r jeden m�glichen


> Zustand eine Klasse erstellt wird.

Ja, so ist das reine Pattern: ein Automat hat Methoden, die

�ber verschiedene Objects eines state-typs (z.B. als enums)
gemappt, bzw. dekoriert werden. Z.B. k�nnte ein Stream-Reader
eine Methode automat.readChar() und die beiden states state.IN
und state.EOF (neben state.START) annehmen k�nnen, die jeweils
ihrerseits eine Methode readChar() besitzen. state wird nun als
state.START initialisiert und automat.state.readChar() liest nun
entweder ein EOF und gelangt in den finalen Zustand state.EOF oder
in den Zustand state.IN, der verlassen wird, wenn ein EOF auftaucht.

> Wie sonst sollte man das State Pattern umsetzen?

An jeder Stelle, an der du das Pattern willst, denn der Automat

besitzt ja die State-Objekte, die wahlweise Methoden dekorieren

(bzw. delegieren) k�nnen (nach reiner Lehre) oder sonstwie
"weiteres behaviour" implementieren.

>>> Und da


>>> bin ich der Meinung, dass durch die vielen Klassen ein wenig der

>>> �berblick leidet.


>>
>> Du kannst den ganzen komplexen Editor auf beliebige Weise mit
>> Status-Mechanismusmen versehen (einem oder mehreren) und dabei
>> die ganze Welt des Polymorphismus und der Dekoration einsetzen.
>
> Ja, aber das entspricht dann halt nicht mehr der Intention des State
> Pattern.

Das State Pattern kann als eine Art Mischform zwischen Dekoration
bzw. Delegation und Vererbung, weil man gewisserma�en die Vererbung
hinter eine Fassade legt.

Du kannst ja auch hier nach reiner Lehre vorgehen. Wenn z.B.
einfach alle deine Graphikobjekte ein Super-Objekt vom Typ

state enthalten (m�ssen), dann kannst du auch die state-Klasse
�berschreiben und Polymorphismus nutzen. Z.B. kannst du auch
ge�nderte State-Objects weiterreichen, in der Art wie man eben
Wrapper-Klassen einsetzt, es ist mindestens "beruhigend" zu
wissen, da� man so auch mal Ausnahmen modellkonform handlen
kann. Du kannst auch immer wahlweise entscheiden, ob du in
jedem Einzelfall state.methodeX() oder methodeX() "aufdeckst".

>>> Dumm ist halt, dass, wenn ich mich einmal auf die entsprechende Variante
>>> (state pattern oder "klassisch") fesgegelegt habe, das nur mit einigem

>>> Aufwand in die andere Variante �berf�hrt werden kann.


>>
>> Versuch halt beides zu verbinden, d.h. die Graphikobjekte in jedem

>> Fall vom Transitionsmechanismus, der zu iher Entstehung f�hrt, zu
>> entkoppeln (wenigstens formal in der Weise, da� du den status in

>> einem Objekt kapselst).
>
> Also etwa ein GraphicObjectEditor, von dem dann die konkreten Editoren
> abgeleitet werden?

Nein, der Editor ist offenbar ein Dialog, der Eingaben sammelt

und auf dem Bildschirm ausgibt (und wom�glich in eine Datenbank),
es ist dann so, da� du einen Automaten m�chtest, der selbst erkennt,

wie lange die Eingabe einem jeweils einzelnen Objekt zugeleitet
werden m�ssen. Dazu brauchst du in der Tat nur ein einzelnes Flag ;)

Ich hatte da neuerdings eher an einen ganzen Undo-Mechanismus
gedacht, der z.B. die zu editierenden Objekte bis zur Fertigstellung

z.B. gestrichelt darstellt und graphische Handles (z.B. das Quadrat

um einen Kreis) hat, und vielleicht auch nichtmodale Dialogboxen, mit
denen man die Farbe live �ndern kann, oder das Ratio einer Ellipse,
in freier Reihenfolge also, usw.

Eine solche Kaskade von Zust�nden m�sste man sehr strukturiert
behandeln, oder man verliert schnell den �berblick...

> Insgesamt war eben die Frage, ob man in diesem Fall das State Pattern
> streng nach Lehrbuch implementieren sollte.

Auf keinen Fall daf�r jedenfalls, um "festzustellen", ob der

Editiervorgang f�r ein Graphikobjekt vollst�ndig ist, das w�re

sicherlich in der Tat grober Unsinn, wie du in deinem Posting
ebenfalls vermutest. Patterns zum Selbszweck bringt nat�rlich nichts.

Aber meine Idee ist ja die oben wieder angedeutete "Mischform".

Man m��te einfach mal konkreter werden, was h�ltst du von
der folgenden Form deines Editors?

public interface Primitive {
void render();
boolean isDone();
void onInputListener(/*...*/);
}

public class Editor {

class Line implements Primitive {

public void render() {
}
public void onInputListener(/*...*/) {
}
public boolean isDone() {
return true;
}
}

java.util.List<Primitive> plist = new java.util.ArrayList <Primitive>();

Primitive editNow = null;

void onInput(/* Line */) {

//
// check if a new Primitive is wanted etc
//

if (null == editNow /* etc */) {
editNow = new Line();
}
else {
if (editNow.isDone()) {
plist.add(editNow);
editNow.render();
editNow = null;
}
else
editNow.onInputListener(/*...*/);
}
}

public static void main(String[] args) {
new Editor();
}
}

Bernd Eckenfels

unread,
Dec 26, 2009, 6:36:02 PM12/26/09
to
Marcus Woletz <marcus...@web.de> wrote:
> einfachtes Beispiel: zeichnen einer Linie, hier etwas vereinfacht
> dargestellt.

ᅵbrigens: wenn man undo/redo unterstᅵtzen muss, dann sollte man sowieso ein
entsprechendes Pattern (Actions) benutzen, das ist mit dem State Pattern
recht vergleichbar.

State Pattern selbst benutze ich nur wenn es auch im Rahmen einer "Strategy"
verwendet werden kann, also viele gleichartige IFs oder case spart.

Gruss
Bernd

Michael Paap

unread,
Dec 26, 2009, 7:22:18 PM12/26/09
to
Am 26.12.2009 16:28, schrieb Marcus Woletz:

> Das ganze kann nun dadurch umgesetzt werden, dass im Objektin einem int
> eine Zustandsnummer gespeichert wird. In den einzelnen Eingabemethode

> (mousePressed, mouseMoved etc.) wird dann abh�ngig vom Zustand die
> jeweilige Aktion ausgef�hrt.

Mal v�llig unabh�ngig von deiner eigentlichen Frage w�rde ich statt der
int-Werte lieber eine entsprechende Enum verwenden.

Dann kannst du n�mlich sicher sein, dass nur g�ltige Werte verwendet
werden und lesbarer ist es auch.

Gru�,
Michael Paap

Bernd Eckenfels

unread,
Dec 26, 2009, 7:32:25 PM12/26/09
to
Michael Paap <ncn...@mpaap.de> wrote:
> Dann kannst du nᅵmlich sicher sein, dass nur gᅵltige Werte verwendet

> werden und lesbarer ist es auch.

Und man kann an den Enum gleich methoden dranhaengen und sich das State
Objekt sparen :)

Gruss
Bernd

Daniel Urban

unread,
Dec 27, 2009, 4:29:19 AM12/27/09
to
"Marcus Woletz"
> Karl Heinz schrieb:

> >> Wird nun alles mit dem state pattern umgesetzt, dann muss f�r jeden
> >> m�glichen Zustand der verschiedenen Objekttypen (Linie, Polylinie,

> >> Polygonlinie, Kreis, Text. etc. pp) eine Klasse erstellt werden.
> >
> > Oh! Geht das nicht anders?
>
> Naja, ich kenne das State Pattern halt so, dass f�r jeden m�glichen

> Zustand eine Klasse erstellt wird. Wie sonst sollte man das State
> Pattern umsetzen?

Ich verstehe das so, dass falls das Verhalten pro State unterschiedlich ist,
ein entsprechendes State Pattern eingesetzt wird. Immerhin haben die States
auch normalerweise ein gemeinsames Interface. Wenn ich lediglich eine
Aufz�hlung von Zust�nden habe, dann kann ich auch eine Enumeration
verwenden.

Letztendlich glaube ich, dass Du hier eigentlich die Frage stellst, warum
man in der Klasse die Funktionalit�t implementiert und nicht au�erhalb, also
auf dem Objekt arbeitet. Die gilt f�r Zust�nde wie f�r Objekte.

Gru�,

Daniel


Daniel Urban

unread,
Dec 27, 2009, 4:32:03 AM12/27/09
to
"Marcus Woletz"

> eine kurze Frage: verwendet ihr immer, wo m�glich, das State pattern?

Nat�rlich nur wenn es sich wirklich um ein entsprechendes Verhalten handelt.

> Ich wollte mich streng an die pattern halten und setzte deshalb in einem
> Grafikeditor das State pattern um.

Wie im Beispiel im Buch "Design Pattern" der GoF?

> Das war mir irgend wann allerdings zu
> stressig, da in meinem Programm zig Objekttypen mit wiederum mehreren

> m�glichen Zust�nden existieren.

Kannst Du mal Beispiele nennen? Mir fallen da f�r einen Grafikeditor nicht
viele ein. Naheliegend ist der Status des Cursors (wie im Beispiel des oben
genannten Buchs).

> Durch das State pattern wird IMO ein

> Programm durch eine gro�e Anzahl zus�tzlicher Klassen aufgebl�ht, und im
> Gegensatz zur Alternativen if-Anweisung und Kodierung der Zust�nde als
> Ganzzahl scheint mir das state pattern auch deutlich un�bersichtlicher.

In dem einem Fall hast Du viele Klassen in dem anderen Fall hast Du eine
Klasse mit Spaghetti-Code. Die if-Anweisnung w�rde f�r mich nur dann Sinn
machen, wenn es wenige Unterscheidungen gibt. Dazu kommt, dass man die
unterschiedlichen Implementierung dann vermutlich auch in die Klasse
reinquetschen w�rde.

> Wie ist eure Meinung dazu: Immer State pattern verwenden, um streng nach
> Regeln zu arbeiten

Welche Regel meinst Du denn? Vielleicht kannst Du die hier mal formulieren?

> und zeigen, dass man "in" ist,

Design Pattern (insbesondere dieses) gibt es schon so lange, dass ich hier
fast schon von "old school" reden w�rde.

Gru�,

Daniel

Marcus Woletz

unread,
Dec 27, 2009, 7:55:02 AM12/27/09
to
Hallo Karl Heinz,

Karl Heinz schrieb:

[...]

> Man müßte einfach mal konkreter werden, was hältst du von

ja, fast exakt so sieht meine bisherige Implementierung aus :-)

Also werde ich wohl auf diesem Weg bleiben.

Und die Frage war jetzt eben, ob ich alle möglichen Zustände in eigene,
von State abgeleitete Klassen auslagern soll.

Danke nochmal für Deine Tipps.

ciao

Marcus

Marcus Woletz

unread,
Dec 27, 2009, 7:49:59 AM12/27/09
to
Hallo Daniel,


Daniel Urban schrieb:
> "Marcus Woletz"
>> eine kurze Frage: verwendet ihr immer, wo möglich, das State pattern?
>
> Natürlich nur wenn es sich wirklich um ein entsprechendes Verhalten


> handelt.
>
>> Ich wollte mich streng an die pattern halten und setzte deshalb in einem
>> Grafikeditor das State pattern um.
>
> Wie im Beispiel im Buch "Design Pattern" der GoF?

kenne ich leider nicht. Ich habe hier "patternorientierte
Softwarearchitektur" und "Entwurfsmuster von Kopf bis Fuß" liegen.

>
>> Das war mir irgend wann allerdings zu
>> stressig, da in meinem Programm zig Objekttypen mit wiederum mehreren

>> möglichen Zuständen existieren.
>
> Kannst Du mal Beispiele nennen? Mir fallen da für einen Grafikeditor nicht


> viele ein. Naheliegend ist der Status des Cursors (wie im Beispiel des oben
> genannten Buchs).

Na ja, jede Grafikprimitive z.B. kann ja während der Erstellung durchaus
in mehreren Zuständen befinden. Einfachster Fall der Linie:

Zustand 1: Objekt erzeugt
Zustand 2: Startpunkt gesetzt
Zustand 3: Endpunkt gesetzt
Zustand 5: Objekt fertiggestellt, in Gesamtzeichnung aufgenommen.

Dann gibt es noch weitere Zustände, wenn die Linie z.B. mit der Maus per
DnD verschoben wird, wenn mit der rechten Maustaste ein Kontextmenü
angezeigt werden soll, wenn das Objekt selektiert ist usw.

Je nach Primitive gibt es durchaus noch einige weitere Zustände. Nun
soll ja nach Musterbeschreibung für jeden Zustand eine Klasse
implementiert werden. Das wären dann für die einfach Linie im
schlechtesten Fall z.B. zehn Klassen.

Für das Dutzend weiterer Primitive wären es dann schon ca. 100 Klassen.

OK, man kann jetzt sicher objektspezifisches Verhalten (z.B.
"DrawSelectedState") in die jeweilige Objektklasse packen und dadurch
für bestimmte Zustände Klassen einsparen. Aber das führt dann IMO zu
weiterer Verwirrung.

Nun kann ich ja durchaus für jede Klasse einen "ImputController"
implementieren, diesen dann per Komposition der Grafikprimitive zufügen
und dann alle E/A-Operationen im InputController behandeln.
Der InputController besitzt dann z.B. eine Methode "mouseMoved". In
dieser Methode werden dann halt, u.a. abhängig vom aktuellen Zustand des
Grafikobjekts bestimmte Reaktionen ausgelöst. Dazu genügen dann jedoch
in der Methode "mouseMoved" nur einige wenige if-Abfragen.
Und, na ja, der "Spaghetticode" würde sich durchaus in Grenzen halten.

public void mouseMoved (MouseEvent e)
{
if (state == NO_POINT_SET)
{
...
}

if (state == START_POINT_SET)
{
...
}

if (state == MOVING)
{
...
}

...
}


[...]


> Welche Regel meinst Du denn? Vielleicht kannst Du die hier mal formulieren?

Die Regel, dass Zustandsmaschinen, also z.B. das Zustandsdiagramm in
UML, mit Hilfe des state patterns implementiert werden sollen?

>
>> und zeigen, dass man "in" ist,
>
> Design Pattern (insbesondere dieses) gibt es schon so lange, dass ich hier

> fast schon von "old school" reden würde.

Na ja, aber wenn nach der reinen Lehre das state pattern verwendet
werden sollte, ich dagegen das Ganze über oben dargestellte Variante
umsetze, könnte jemand, der den Quelltext anschaut, denken, dass ich das
state pattern überhaupt nicht kenne...

>
> Gruß,
>
> Daniel
>

ciao

Marcus

Patrick Roemer

unread,
Dec 27, 2009, 8:31:09 AM12/27/09
to
Responding to Marcus Woletz:

> Na ja, jede Grafikprimitive z.B. kann ja w�hrend der Erstellung durchaus
> in mehreren Zust�nden befinden. Einfachster Fall der Linie:


>
> Zustand 1: Objekt erzeugt
> Zustand 2: Startpunkt gesetzt
> Zustand 3: Endpunkt gesetzt
> Zustand 5: Objekt fertiggestellt, in Gesamtzeichnung aufgenommen.
>

> Dann gibt es noch weitere Zust�nde, wenn die Linie z.B. mit der Maus per
> DnD verschoben wird, wenn mit der rechten Maustaste ein Kontextmen�


> angezeigt werden soll, wenn das Objekt selektiert ist usw.
>

> Je nach Primitive gibt es durchaus noch einige weitere Zust�nde. Nun
> soll ja nach Musterbeschreibung f�r jeden Zustand eine Klasse
> implementiert werden. Das w�ren dann f�r die einfach Linie im


> schlechtesten Fall z.B. zehn Klassen.
>

> F�r das Dutzend weiterer Primitive w�ren es dann schon ca. 100 Klassen.


>
> OK, man kann jetzt sicher objektspezifisches Verhalten (z.B.
> "DrawSelectedState") in die jeweilige Objektklasse packen und dadurch

> f�r bestimmte Zust�nde Klassen einsparen. Aber das f�hrt dann IMO zu
> weiterer Verwirrung.

Das waere wahrscheinlich ein Ansatz, den ich mir zunaechst anschauen
wuerde: In der abstrakten Primitive-Klasse (private) Zustaende
definieren, die (mehr oder minder) auf alle Primitive zutreffen (fuer
die Erstellung: UNINITIALIZED, REALIZING, REALIZED), und aus denen
wiederum an abstrakte Methoden von Primitive delegieren. Warum sollte
das zu weiterer Verwirrung fuehren?

Eine andere Frage waere, ob man diese Verantwortlichkeiten tatsaechlich
alle in eine Klasse(nhierarchie) packen will: Ist eine nicht realisierte
Linie tatsaechlich schon eine solche, und sollte eine Linie
grundsaetzlich etwa darueber Bescheid wissen, dass sie in selektiertem
Zustand auf rechten Mausklick ein Kontextmenue anzeigen sollte, oder
koennte man das in entsprechende Builder- bzw.
"Selected"-Decorator-Klassen(nhierarchien) verschieben?

> Nun kann ich ja durchaus f�r jede Klasse einen "ImputController"
> implementieren, diesen dann per Komposition der Grafikprimitive zuf�gen


> und dann alle E/A-Operationen im InputController behandeln.
> Der InputController besitzt dann z.B. eine Methode "mouseMoved". In

> dieser Methode werden dann halt, u.a. abh�ngig vom aktuellen Zustand des
> Grafikobjekts bestimmte Reaktionen ausgel�st. Dazu gen�gen dann jedoch


> in der Methode "mouseMoved" nur einige wenige if-Abfragen.

> Und, na ja, der "Spaghetticode" w�rde sich durchaus in Grenzen halten.


>
> public void mouseMoved (MouseEvent e)
> {
> if (state == NO_POINT_SET)
> {
> ...
> }
>
> if (state == START_POINT_SET)
> {
> ...
> }
>
> if (state == MOVING)
> {
> ...
> }
>
> ...
> }

Wenn nur die konkrete Klasse den "State" haelt, muesstest Du dieses
switch-Muster doch schon wieder ueberall fuer mouseClicked(),
keyPressed(), etc. duplizieren, oder?

> Die Regel, dass Zustandsmaschinen, also z.B. das Zustandsdiagramm in
> UML, mit Hilfe des state patterns implementiert werden sollen?

Das State-Pattern hat AFAICS nicht viel mit Zustandsautomaten zu tun.

Viele Gruesse,
Patrick

Daniel Urban

unread,
Dec 27, 2009, 8:54:49 AM12/27/09
to
"Marcus Woletz"
> Daniel Urban schrieb:
> > Kannst Du mal Beispiele nennen? Mir fallen da f�r einen Grafikeditor
> > nicht
> > viele ein. Naheliegend ist der Status des Cursors (wie im Beispiel des
> > oben
> > genannten Buchs).
>
> Na ja, jede Grafikprimitive z.B. kann ja w�hrend der Erstellung durchaus
> in mehreren Zust�nden befinden. Einfachster Fall der Linie:

>
> Zustand 1: Objekt erzeugt
> Zustand 2: Startpunkt gesetzt
> Zustand 3: Endpunkt gesetzt
> Zustand 5: Objekt fertiggestellt, in Gesamtzeichnung aufgenommen.

Da hast Du dann doch schon mal ein interessantes Abstraktionsniveau f�r ein
Interface. Wobei ich das verk�rzen w�rde auf:

1. Objekt ausgew�hlt
2. Startpunkt gesetzt
3. Endpunkt gesetzt

das m�sste meiner Meinung nach reichen.

> F�r das Dutzend weiterer Primitive w�ren es dann schon ca. 100 Klassen.

Wieso? Die werden sich wohl nicht sonderlich unterscheiden? Die Zust�nde
h�ngen doch von den Operationen ab, die man auf den Objekten machen kann.
Diese werden sich auch alle im Interface der States wiederfinden m�ssen.

Wenn ich mir zum Beispiel den Grafikeditor von MS "Paint" anschaue, w�rde
ich sch�tzen, dass es da vielleicht 3-10 Zust�nde gibt. Aber vielleicht
vergese ich hier auch irgend etwas.

[...]


> Der InputController besitzt dann z.B. eine Methode "mouseMoved". In

> dieser Methode werden dann halt, u.a. abh�ngig vom aktuellen Zustand des

> Grafikobjekts bestimmte Reaktionen ausgel�st. Dazu gen�gen dann jedoch


> in der Methode "mouseMoved" nur einige wenige if-Abfragen.

> Und, na ja, der "Spaghetticode" w�rde sich durchaus in Grenzen halten.

Die If-Anweisungen m�ssen doch immer proportional zu der Anzahl der Klassen
im State-Pattern sein. Gibt es viele Klassen in dem angewandten Pattern, so
muss im anderen Fall auch viele If-Anweisungen geben. Ob 100 If-Anweisungen
Spaghetticode sind, musst Du dann selber entscheiden. vorausgesetzt ist
nat�rlich immer, dass sich das Verhalten immer unterscheidet.

[...]
> > Welche Regel meinst Du denn? Vielleicht kannst Du die hier mal
> > formulieren?
>
> Die Regel, dass Zustandsmaschinen, also z.B. das Zustandsdiagramm in
> UML, mit Hilfe des state patterns implementiert werden sollen?

Mal aus dem o.g. Buch zitiert:

"Allow an object to alter its behavior when its internal state changes. The
object will appear to change its class."

Wenn der erst Teil wegf�llt, d�rfte auch f�r mich der Einsatz einer
Enumaration sinnvoller sein, insbesondere wenn es nur eine Aktion "accept"
gibt, die den n�chsten Zustand setzt. In Deinem Beispiel wird aber doch viel
mehr gemacht. Da wird gezeichnet, da werden sich Koordination gemerkt,
Objekte gespeichert usw. je nach Zustand.

Gru�,

Daniel

Daniel Urban

unread,
Dec 27, 2009, 9:54:33 AM12/27/09
to
"Marcus Woletz"
[...]

> public void mouseMoved (MouseEvent e)
> {
> if (state == NO_POINT_SET)
> {
> ...
> }
>
> if (state == START_POINT_SET)
> {
> ...
> }
>
> if (state == MOVING)
> {
> ...
> }
>
> ...
> }
>
>
> > Welche Regel meinst Du denn? Vielleicht kannst Du die hier mal
> > formulieren?
>
> Die Regel, dass Zustandsmaschinen, also z.B. das Zustandsdiagramm in
> UML, mit Hilfe des state patterns implementiert werden sollen?

Da ich nicht ganz sicher bin, ob Du das gleiche Verst�ndnis von dem
State-Pattern hast, w�rde ich gerne ein Hallo Welt Beispiel zur Diskussion
verwenden, falls das okay ist?

Beispiel (Pseudonotation):

class Mensch {
IMuttersprache muttersprache;
sageHalloWelt() {
muttersprache.sageHallowelt();
}
}

interface Muttersprache {
sageHalloWelt()
}

class DeutscheMuttersprache implements Muttersprache {
sageHalloWelt() {
print("Hallo Welt");
}
}
...

Das Beispiel ist so gew�hlt, dass es keinen Status�bergang gibt. Die
Muttersprache kann nicht wechseln. Mein Mensch hat auch nur eine
Muttersprache und kann nur einen Satz sprechen (didaktische Vereinfachung).

Dein Code, wenn ich das richtig verstehe, w�rde dann so aussehen:

class Mensch {
int muttersprache;
sageHalloWelt() {
if (muttersprache == 1) { // deutsch
print("Hallo welt");
}
else if ...
}
}

Du kannst nat�rlich auch das print noch inlinen, was aber den Spaghetti-Code
nur gr��er machen w�rde, weswegen ich schon mal angenommen habe, dass Du das
Verhalten zumindest in Methoden faktorisierst.

Die Anzahl der Klassen und Methoden bzw. geinlinte Code-Stellen ist hier
erst einmal identisch. Wenn nun eine zweite Methode sageAufwiedersehen()
hinzukommt, bleibt die Anzahl der Klassen gleich, die Anzahl der Methoden
bzw. Codestellen wird aber proportional wachsen.

Was sind die Vorteile der Verwendung von Klassen? Das Verhalten eines
Objekts ist im Objekt implementiert und nicht verstreut auf zahlreiche
andere Klassen. F�r Objekte wie Auto, Haus, Mensch usw. ist das vermutlich
jedem aus dem Unterrichten zur Objektorientierung gel�ufig, die Ausweitung
auf Zust�nde (keine Dinge) ist nur die konsequente Weiterf�hrung.

Falls unser Verst�ndnis doch nicht zu verschieden ist, m�sstest Du mich doch
noch einmal da�rber informierten, warum die gro�e If-Anweisungen besser
gefallen, als entsprechend viele Klassen? Die Anzahl der Code-Zeilen kann es
eigentlich nicht sein, da die nicht wesentlich unterschiedlich sein d�rften.

Gru�,

Daniel

Karl Heinz

unread,
Dec 27, 2009, 1:16:17 PM12/27/09
to
Marcus Woletz schrieb:

>> ... }



> ja, fast exakt so sieht meine bisherige Implementierung aus :-)
>
> Also werde ich wohl auf diesem Weg bleiben.
>

> Und die Frage war jetzt eben, ob ich alle m�glichen Zust�nde in eigene,


> von State abgeleitete Klassen auslagern soll.

Habe grade mal noch etwas weiter rumgespielt.

Die m�glicherweise entstandene Form der reinen Lehre k�nnte demnach
wie das folgende ausarten ;)

Der Code l�uft wenn man den als Editor.java ablegt. Man tippt
dann irgendwann mal 'line' mit Enter ein und macht drei weitere
Eingaben und zuletzt 'exit' wodurch der Code die Statemachine
durchl�uft und die in der Primitiven gelieferten Jobs erledigt.

Aber wie gesagt, in der gemischten Lehre mu� man die State-Logik,
auch nachdem man eine hat, nicht in jedem Fall benutzen...


public class Editor {

abstract class Job {

public abstract void start();
public abstract void edit();
public abstract void done();
}

public enum State {

START {
public State transition(Job job) {
job.start();
return EDIT; }
},
EDIT {
public State transition(Job job) {
job.edit();
return DONE; }
},
DONE {
public State transition(Job job) {
job.done();
return DONE; }
};

abstract State transition(Job job);
}

public interface Primitive {
void render();
boolean isDone();

void onInputListener(String input);
}

class Line implements Primitive {

State s = State.START;

boolean done = false;

Job job = new Job() {

public void done() {
System.out.println("Line.done");
}

public void edit() {
System.out.println("Line.edit");
}

public void start() {
System.out.println("Line.start");
}
};

public void onInputListener(String input) {

if (input.startsWith("done")) {
done = true;
}
else {

s = s.transition(job);
}
}

public boolean isDone() {
return done;
}

public void render() {


}
}

java.util.List<Primitive> plist = new java.util.ArrayList <Primitive>();

Primitive editNow = null;

void onInputListener(String input) {

if (null == editNow) {
if (input.startsWith("line")) {


editNow = new Line();
}
}
else {
if (editNow.isDone()) {
plist.add(editNow);
editNow.render();
editNow = null;
}

else {
editNow.onInputListener(input);
editNow.render();


}
}
}

public static void main(String[] args) {

Editor e = new Editor();

java.util.Scanner in = new java.util.Scanner(System.in);

for (String input = "";
! input.startsWith("exit");
input = in.nextLine()) {
e.onInputListener(input);
}
}
}

Karl Heinz

unread,
Dec 27, 2009, 3:19:28 PM12/27/09
to

Superseded:
die Jobs haben nun Zugriff auf das Elternobjekt,
die Statusfolge wird von aussen gesetzt und
es wird der "wahre" Input verarbeitet/ausgegeben.

Marcus Woletz schrieb:

>> ... }



> ja, fast exakt so sieht meine bisherige Implementierung aus :-)
>
> Also werde ich wohl auf diesem Weg bleiben.
>

> Und die Frage war jetzt eben, ob ich alle m�glichen Zust�nde in eigene,


> von State abgeleitete Klassen auslagern soll.

Habe grade mal noch etwas weiter rumgespielt.

Die m�glicherweise entstandene Form der reinen Lehre k�nnte

demnach schnell so wie das folgende ausarten ;)

Der Code l�uft wenn man den als Editor.java ablegt. Man tippt
dann irgendwann mal 'line' mit Enter ein und macht drei weitere
Eingaben und zuletzt 'exit' wodurch der Code die Statemachine
durchl�uft und die in der Primitiven gelieferten Jobs erledigt.

Aber wie gesagt, in der gemischten Lehre mu� man die State-Logik,
auch nachdem man eine hat, nicht in jedem Fall benutzen...



public class Editor {

abstract class Job {

protected final Primitive primitive;

protected Job(Primitive p) {this.primitive = p; }

public abstract State start();
public abstract State edit();
public abstract State done();
}

public enum State {

START {
public State transition(Job job) {

return job.start();


}
},
EDIT {
public State transition(Job job) {

return job.edit();


}
},
DONE {
public State transition(Job job) {

return job.done();
}
};

abstract State transition(Job job);
}

public interface Primitive {

void render();
void setDone();


boolean isDone();
void onInputListener(String input);
}

class Line implements Primitive {

private State s = State.START;

private boolean done = false;

String input = "";

Job job = new Job(this) {

public State start() {
System.out.println("Line.start + " + input);
return State.EDIT;
}
public State edit() {
System.out.println("Line.edit + " + input);
return State.DONE;
}
public State done() {
System.out.println("Line.done + " + input);
primitive.setDone();
return State.DONE;
}
};

public void onInputListener(String input) {

this.input = input;

s = s.transition(job);
}

public void setDone() {
done = true;


}
public boolean isDone() {
return done;
}

public void render() {
}
}


java.util.List<Primitive> plist = new java.util.ArrayList <Primitive>();

Primitive editNow = null;


void onInputListener(String input) {

if (null == editNow) {
if (input.startsWith("line")) {

editNow = new Line();
}
}
else {
if (editNow.isDone()) {
plist.add(editNow);
editNow.render();
editNow = null;
}

else {
editNow.onInputListener(input);
editNow.render();


}
}
}

public static void main(String[] args) {

Patrick Roemer

unread,
Dec 27, 2009, 7:48:08 PM12/27/09
to
Responding to myself:

> Eine andere Frage waere, ob man diese Verantwortlichkeiten tatsaechlich
> alle in eine Klasse(nhierarchie) packen will: Ist eine nicht realisierte
> Linie tatsaechlich schon eine solche, und sollte eine Linie
> grundsaetzlich etwa darueber Bescheid wissen, dass sie in selektiertem
> Zustand auf rechten Mausklick ein Kontextmenue anzeigen sollte, oder
> koennte man das in entsprechende Builder- bzw.
> "Selected"-Decorator-Klassen(nhierarchien) verschieben?

Ich hab's spasseshalber mal mit einer minimalistischen Version
ausprobiert, die nichts weiter kann, als Linien, Kreise, Ellipsen,
Rechtecke und Polygone zu malen. (Also keine Selektion, etc., nur das
reine Ausgangsbeispiel.)

Dabei habe ich, wie oben vorgeschlagen, die Erzeugung in eigene Klassen
ausgelagert. (Und das ist keine reine Duplizierung der Shape-Hierarchie:
Es gibt nur ein Ellipsen-Shape, aber zwei Builder (Kreis und Ellipse),
die solche Dinger erzeugen. Genausogut koennte man sich vorstellen, dass
es Shapes gibt, die gar nicht direkt ueber einen Builder erzeugt werden,
sondern nur als Komponenten "groesserer" Shapes existieren.)

Dabei fiel dann auf, dass die Builder eigentlich alle lediglich Points
aufsammeln - beim Polygon solange, bis mindestens drei feststehen und
bei der letzten Auswahl die rechte Maustaste geklickt wird, bei allen
anderen genau zwei. Und gemalt wird immer, sobald es mindestens zwei
Points gibt (wovon der letztere noch nicht feststehen muss, sondern auch
temporaer durch Mausgefuchtel ohne Klick entstehen kann: "pending").
Also habe ich das in einen PointCollector rausfaktoriert, und stand auf
einmal ohne nennenswerte Zustandswechsel da.

public abstract class PointCollectingShapeBuilder
implements ShapeBuilder {

public void mouseClick(MouseEvent evt) {
collector.add(evt.getPoint());
if(finished(collector.pointCount(), evt.getButton())) {
editorModel.add(shape(collector.points()));
editorModel.builder(null);
}
else {
changed();
}
}

public void mouseMove(MouseEvent evt) {
collector.pending(evt.getPoint());
changed();
}

public void draw(Graphics2D graphics) {
Point[] points = collector.points();
if(points.length > 1) {
draw(graphics, points);
}
}

protected abstract void draw(Graphics2D graphics, Point[] points);
protected abstract boolean finished(int pointCount, int button);
protected abstract Shape shape(Point[] points);

// ...
}

<maus>Sieht komisch aus, funktioniert aber.</maus>

Fuer eine reale Applikation ist dieses Design wahrscheinlich kompletter
Muell, aber fuer die Minimal-"Requirements" tut es (und das Hinzufuegen
neuer Shapes und/oder Builders und neuer "Features" wie Farbauswahl war
soweit auch erstaunlich schmerzfrei.) Daher bestaerkt mich das schon in
meiner bisherigen Ueberzeugung, dass das State-Pattern durchaus sinnvoll
sein kann, wenn die Voraussetzungen fuer seinen Einsatz gegeben sind,
dass das aber eben aeusserst selten der Fall ist: Meist findet man
vorher andere Abstraktionen (und sei es schlicht "normaler"
Polymorphismus), die duplizierten State-Dispatch in mehreren Methoden
einer Klasse gar nicht erst entstehen lassen.

Der einzige potentielle Anwendungsfall, den ich dafuer seit langer Zeit
gesehen habe, waren BTree-Nodes, die viel unterschiedliches taten, je
nachdem, ob sie schon von Platte geladen waren, oder nicht. (Also
eigentlich recht aehnlich zum GoF-TCP-Beispiel.) Wenn es denn mal
angebracht ist, wuerde ich es duplizierten if-Kaskaden oder
enum-Switches aber wohl meist vorziehen.

Viele Gruesse,
Patrick

Heiner Kücker

unread,
Jan 12, 2010, 10:31:34 AM1/12/10
to
Marcus Woletz wrote:
> eine kurze Frage: verwendet ihr immer, wo möglich, das State pattern?

Ich muss Zugeben, dass ich es selten verwende.

> Ich wollte mich streng an die pattern halten und setzte deshalb in einem
> Grafikeditor das State pattern um. Das war mir irgend wann allerdings zu
> stressig, da in meinem Programm zig Objekttypen mit wiederum mehreren
> möglichen Zuständen existieren. Durch das State pattern wird IMO ein
> Programm durch eine große Anzahl zusätzlicher Klassen aufgebläht,

Durch innere Klassen wird es besser.

> und im
> Gegensatz zur Alternativen if-Anweisung und Kodierung der Zustände als
> Ganzzahl

Ab Java5 wären Enums besser geeignet.

> scheint mir das state pattern auch deutlich unübersichtlicher.

Das ist meiner Meinung nach eine Frage der Gewöhnung.

> Ich würde sogar so weit gehen und das state pattern als anti pattern
> einordnen. Es ist einfach unhandlich. Ich würde das state pattern ja
> gerne grundsätzlich einsetzen, aber mir gefällt's einfach nicht.

Hm.

> Wie ist eure Meinung dazu: Immer State pattern verwenden, um streng nach
> Regeln zu arbeiten und zeigen, dass man "in" ist, oder bei Bedarf auch
> die gute alte Variante (wie beschrieben) verwenden?

Ich würde sagen, Anwendung je nach Bedarf.

Der wesentliche Unterschied ist, dass beim State-Pattern das Verhalten
umgeschaltet wird. Das Weiterschalten auf den nächsten Zustand
ist eine weitere Angelegenheit.

Wenn Zustände also nur umgeschalten werden sollen,
es aber keine weiteren Aktionen gibt, ist die alte Tabellen- und Werte-
Lösung
in Ordnung.

Handelt es sich aber bei dem abzubildenden Modell um eine
Taschenlampe mit den möglichen Zuständen Aus, An und Blinkend,
so könnte eine show-Methode in der Zustands-Klasse Blinkend
über einen Timer das Blinken realsisieren.

Für den Aufrufer der schow-Methode ist das konkrete Verhalten
über Polymorphie variant und gekapselt.

> Marcus

Grüsse
Heiner
http://www.heinerkuecker.de/Sudoku.html

0 new messages