Discussion:
strategy enum pattern
(zu alt für eine Antwort)
Johannes Lichtenberger
2010-12-04 00:55:36 UTC
Permalink
Hallo,

ich habe folgenes enum:

/** XPath enum to determine if current item is found by an XPath
expression or not. */
enum XPathState {
/** Item is found. */
ISFOUND(StateType.ISFOUND),

/** Default: Item is not found. */
ISNOTFOUND(StateType.ISNOTFOUND);

/** {@link StateType}. */
private final StateType mStateType;

/**
* Constructor.
*
* @param paramType
* private {@link StateType}
*/
XPathState(final StateType paramType) {
mStateType = paramType;
}

/**
* Set stroke.
*
* @param paramApplet
* Processing {@link PApplet} core.
* @param paramColor
* The color to use.
*/
void setStroke(final PApplet paramApplet, final float paramColor) {
mStateType.setStroke(paramApplet, paramColor);
}

/** Determines state of XPath expression evaluation. */
private enum StateType {

/** Item is found. */
ISFOUND {
@Override
void setStroke(final PApplet paramApplet, final float
paramColor) {
paramApplet.stroke(1f);
}
},

/** Default: Item is not found. */
ISNOTFOUND {
@Override
void setStroke(final PApplet paramApplet, final float
paramColor) {
paramApplet.stroke(paramColor);
}
};

/**
* Set stroke.
*
* @param paramApplet
* Processing {@link PApplet} core.
* @param paramColor
* The color to use.
*/
abstract void setStroke(final PApplet paramApplet, final
float paramColor);
}
}

und eine XPathState Instanz:

/** State which determines if current item is found by an XPath
expression or not. */
private transient XPathState mXPathState = XPathState.ISNOTFOUND;

Was ist denn der großartige Unterschied zwischen:

switch (mXPathState) {
case ISFOUND:
mParent.stroke(1f);
break;
case ISNOTFOUND:
mParent.stroke(mCol);
break;
default:
throw new AssertionError("XPathState not known!");
}

Das war bevor ich das "strategy enum pattern" verwendet habe, also als
es noch einfach enum XPathState { ISFOUND, ISNOTFOUND }; war und das danach:

mXPathState.setStroke(mParent, mCol);

Ersteres klappt, d.h. die richtige Farbe wird für das Zeichnen genommen,
letzteres nimmt immer 1f, also schwarz, egal ob es nun ISFOUND oder
ISNOTFOUND nach einer Änderung mittles

/**
* Set XPath state.
*
* @param paramState
* set state to this value
*/
void setXPathState(final XPathState paramState) {
mXPathState = paramState;
}

ist. Ich nehme an ein simpler Fehler bzw. geistige Umnachtung, vll.
fällt es mir morgen auch selbst auf oder ich muss den Debugger wieder
bemühen...

Viele Grüße,
Johannes
Johannes Lichtenberger
2010-12-04 02:14:23 UTC
Permalink
Man sollte wohl auch int statt float als Parameter für das Setzen der
Farbe nehmen, hat sich also erledigt ;-)

Viele Grüße,
Johannes
Johannes Lichtenberger
2010-12-04 20:07:50 UTC
Permalink
Ich denke das Pattern ist aber auch nicht immer sinnvoll, oder? Bspw.
sind bei unserem XML-Datenbanksystem die Knotentypen als enum definiert,
dann ist es denke ich nicht falsch über die Knotentypen zu switchen, und
abhängig vom Knotentyp einfach irgendwas zu machen.

Viele Grüße,
Johannes
Patrick Roemer
2010-12-05 01:20:15 UTC
Permalink
Post by Johannes Lichtenberger
Ich denke das Pattern ist aber auch nicht immer sinnvoll, oder? Bspw.
sind bei unserem XML-Datenbanksystem die Knotentypen als enum definiert,
dann ist es denke ich nicht falsch über die Knotentypen zu switchen, und
abhängig vom Knotentyp einfach irgendwas zu machen.
Hmnja, aber IMHO zaeumst Du das Pferd von hinten auf. Es ist eigentlich
recht irrelevant, dass es sich um Enums handelt, das sehe ich eher als
Implementierungsdetail, fuer das einem der Compiler etwas Zucker zur
Verfuegung stellt - u.a. halt Verwendbarkeit in einem switch-Statement.

Strategy heisst: "Define a family of algorithms, encapsulate each one,
and make them interchangeable. Strategy lets the algorithm vary
independently from clients that use it." [GoF] Das kann man als Enum
implementieren. Wenn man aber keinen Anwendungsfall fuer eine Strategy
hat, kann man noch so viel Enum zur Hand haben, es macht dann trotzdem
keinen Sinn. Und das ist offenkundig bei den Knotentypen der Fall - die
sind generisch. Je nach konkretem Anwendungsfall koennte es vielleicht
auch mal sinnvoll sein, polymorphen Dispatch ueber einer nach
Knotentypen organisierten Klassenfamilie zu organisieren (Visitor waere
dann als Pattern wahrscheinlicher als Strategy), aber ein solcher
Umstand war aus Deinem Beispiel nicht ablesbar.

Viele Gruesse,
Patrick
HeinerK
2010-12-08 07:31:59 UTC
Permalink
strategy enum pattern

Als ich das gestern gelesen habe, dachte ich
'was für ein Unsinn':

Ein Enum dient zur Realisierung der Typsicherheit eines
Eigenschaftsmerkers der ohne Enum über einen nicht
typsicheren int-Wert realisiert worden wäre.

Insofern ist die Möglichkeit, Enums in switch-Statements
verwenden zu können logisch und richtig, weil das Verhalten
ausserhalb der Enums realisiert ist.

Das Strategy-Pattern dient zur Realisierung eines varianten
Verhaltens mit den Mitteln der Polymorphie (habe ich es
jetzt richtig geschrieben?).

Zur Realisierung des Strategy-Pattern muss ich ein Interface
oder eine abstrakte Ober-Klasse (könnte nicht mal jemand
einen zusammenfassenden Begriff dafür festlegen)
implementieren.

Das implementierte Interface bzw die abstrakte Ober-Klasse
bietet mir automatisch Typsicherheit, weshalb die
Typsicherheit des Enums hier redundant ist.

Soweit also 'Unsinn'.


Aber ein Enum bietet mir noch einige vom Java-Compiler per
Code-Generierung erzeugte Funktionalität:

Ich verweise dazu mal auf das Java5-Buch von Friedrich Esser:

http://www.amazon.de/Das-Tiger-Release-Generics-Concurrent-Programming/dp/3898424596/ref=sr_1_4?ie=UTF8&s=books&qid=1291791200&sr=1-4


1. Die Methode values() liefert mir alle Implementierungen.

Das kann ich mal gebrauchen, wenn ich ein bisschen pfusche,
also doch Verhalten ausserhalb der
Strategy-Implementierungsklassen realisiere oder wenn ich
eine Art Plugin-Mechanismus mit Auswahl des Plugins
realisieren möchte.

Ich verweis hierzu auf das Java6-Service-Provider-API

http://download.oracle.com/javase/6/docs/technotes/guides/jar/jar.html#Overview


2. Beschaffen einer Instanz mit der Methode valueOf(String s)

Das wäre sinnvoll für die Provider-Auswahl, siehe vorigen Punkt.


3. Eine toString()-Methode, die den literalen Namen des Enums
zurückgibt

Ich glaube, dynamische Sprachen bieten solch ein Feature.

Es ist immer lästig, bei einem Guard jedesmal den Namen des
zu schützenden Parameters zu wiederholen:

public void tuwas(
String str )
{
if ( str == null )
{
throw new IllegalArgumentException(
"Parameter str is null" );
}

Mit einem Feature, den literalen Namen des Paramters zu
ermitteln, könnte man hier redundanten Code sparen.


4. Lieferung einer Ordnungsnummer über die Methode int ordinal()

Dafür wüsste ich keine über die Enum-Möglichkeiten hinaus
gehenden Verwendungen.


5. Garantierte Unveränderlichkeit

Das kann wichtig für Multithreading und sicheres
Programmieren sein.


6. Einmaligkeit (Singleton-Garantie)

Für Verhalten ohne Status sicher sinnvoll.

Ein Enum ist somit immer auch ein Fleigengewicht.


7. Sortierbarkeit über implements Comparable

8. Serialisierbarkeit über implements Serializable



Aufgrund dieser vorgefertigten Infrastruktur sehe ich das
strategy enum pattern doch nicht als 'Unsinn' an.


Siehe auch:

http://www.angelikalanger.com/Articles/EffectiveJava/28.Enums/28.Enums.html


Grüsse
Heiner
HeinerK
2010-12-08 07:44:40 UTC
Permalink
Post by Johannes Lichtenberger
strategy enum pattern
    Ein Enum ist somit immer auch ein Fleigengewicht.
Natürlich ist es ein Fliegengewicht.


Eigentlich müsste es strategy enum idiom heissen,
weil es nur in Java umsetzbar ist.

Soweit ich weiss, gibt es diese Möglichkeit weder
in C++ noch in C#.

Java hat hier gut gepunktet.
Post by Johannes Lichtenberger
Grüsse
Heiner
Patrick Roemer
2010-12-09 00:26:31 UTC
Permalink
Post by HeinerK
Post by Johannes Lichtenberger
strategy enum pattern
Ein Enum ist somit immer auch ein Fleigengewicht.
Natürlich ist es ein Fliegengewicht.
Kann man dafuer nutzen, aber eigentlich sind Enums erst mal nur so
fliegenwichtig wie jedes andere Objekt auch. Zum GoF-Flyweight-Pattern
(das einen Verhau aus Factory, Composite und einem Pool aus Objekten,
die als Blattknoten innerhalb der Composite-Struktur wiederverwendet
werden, beschreibt) fehlt da zumindest noch einiges.
Post by HeinerK
Eigentlich müsste es strategy enum idiom heissen,
weil es nur in Java umsetzbar ist.
Soweit ich weiss, gibt es diese Möglichkeit weder
in C++ noch in C#.
Java hat hier gut gepunktet.
Naja... Javatypisch eine Spezialloesung fuer einen Sonderfall, der sich
ohne grosse Probleme in die Legacy einfuegen laesst. Sicher nuetzlich,
aber grosser Wurf geht anders. Als Gegenentwurf halt mal wieder Scala
mit case classes, pattern matching und "sealed"-Modifier: Kann fast
alles was Enums bieten out-of-the-box (#values() muesste man von Hand
implementieren, oder auf eine Library zurueckgreifen), ist aber deutlich
generischer.

Viele Gruesse,
Patrick
HeinerK
2010-12-09 09:41:45 UTC
Permalink
Post by Patrick Roemer
Eigentlich m sste es strategy enum idiom heissen,
weil es nur in Java umsetzbar ist.
Soweit ich weiss, gibt es diese M glichkeit weder
in C++ noch in C#.
Java hat hier gut gepunktet.
Naja... Javatypisch eine Spezialloesung fuer einen Sonderfall, der sich
ohne grosse Probleme in die Legacy einfuegen laesst. Sicher nuetzlich,
aber grosser Wurf geht anders. Als Gegenentwurf halt mal wieder Scala
mit case classes, pattern matching und "sealed"-Modifier: Kann fast
alles was Enums bieten out-of-the-box (#values() muesste man von Hand
implementieren, oder auf eine Library zurueckgreifen), ist aber deutlich
generischer.
Ja, sicher ist Scala besser.

Bücher liegen auf meinem Tisch,
aber zur Zeit mehr als Staubfänger.

Ich habe zum Thema noch zwei interessante Links gefunden:

http://blog.ralscha.ch/?paged=8

http://whyjava.wordpress.com/2010/06/17/applying-design-patterns-with-java-enums/
Post by Patrick Roemer
Viele Gruesse,
Patrick
Danke
Heiner
Michael Paap
2010-12-08 10:48:09 UTC
Permalink
Post by HeinerK
Zur Realisierung des Strategy-Pattern muss ich ein Interface
oder eine abstrakte Ober-Klasse (könnte nicht mal jemand
einen zusammenfassenden Begriff dafür festlegen)
implementieren.
Deklarieren. Der zusammenfassende Begriff, denn du suchst, ist
"abstrakter Supertyp".

Gruß,
Michael
Patrick Roemer
2010-12-09 00:05:01 UTC
Permalink
Post by HeinerK
Ein Enum dient zur Realisierung der Typsicherheit eines
Eigenschaftsmerkers der ohne Enum über einen nicht
typsicheren int-Wert realisiert worden wäre.
Das halte ich fuer eine sehr C-artige Denkweise. Ein Enum ist fuer mich
eine statisch festgelegte Menge von *Objekten* mit einem gemeinsamen
Obertyp, auf die ueber eindeutige Namen direkt zugegriffen werden kann.
Ohne Enums als Sprachfeature wuerde man sowas halt als Implementierung
des "typesafe enum"-Patterns realisieren. (Viel anderes macht der
Compiler ja auch nicht.)

Es gibt den Sonderfall, dass die Objekte dieser Menge keinerlei Zustand
oder Verhalten haben, und nur dieser Sonderfall laesst sich ueber
int-Werte abbilden - es sei denn, man will das Verhalten ueber x
switch-Statements streuen, von Zustand mal gar nicht zu reden.
Post by HeinerK
Insofern ist die Möglichkeit, Enums in switch-Statements
verwenden zu können logisch und richtig, weil das Verhalten
ausserhalb der Enums realisiert ist.
Sicher. Im Fall einer Strategy ist das aber eben nicht relevant, da die
Strategy doch gerade das Verhalten ist (das variiert werden soll). Wenn
ich ueber solche Dinger noch extern dispatche, wuerde ich es
wahrscheinlich schon nicht mehr "Strategy" nennen (und mir ueberlegen,
ob mein Design noch stimmt).
Post by HeinerK
Zur Realisierung des Strategy-Pattern muss ich ein Interface
oder eine abstrakte Ober-Klasse (könnte nicht mal jemand
einen zusammenfassenden Begriff dafür festlegen)
implementieren.
Das implementierte Interface bzw die abstrakte Ober-Klasse
bietet mir automatisch Typsicherheit, weshalb die
Typsicherheit des Enums hier redundant ist.
Um die geht es dann auch nicht mehr primaer. Die Implementierung einer
Strategy als Enum (bzw. in pre-Java5 halt eine Verknuepfung von
Strategy- und Enum-Pattern) bietet sich dann an, wenn die Strategy
keinen Zustand benoetigt, man die Menge der moeglichen
Strategy-Varianten von vornherein festlegen (und keine Erweiterungen
zulassen) will, und Benutzern moeglichst direkten, "benamsten" Zugriff
bieten moechte.

Das von Dir erwaehnte Interface gaebe es dann ueblicherweise auch gar
nicht als eigenstaendige Entitaet (es sei denn, man wollte doch noch
Erweiterungen der Menge zulassen) - das waeren abstrakte Methoden in der
Enum-Deklaration, die von den konkreten Enums implementiert wuerden.
Post by HeinerK
5. Garantierte Unveränderlichkeit
Noe. :) Enums mit veraenderlichem Zustand sind zwar sicherlich ein
Rezept fuer Katzenjammer, nichtsdestotrotz durchaus moeglich.

Viele Gruesse,
Patrick
Paul Ebermann
2010-12-09 11:06:09 UTC
Permalink
Post by Patrick Roemer
Post by HeinerK
5. Garantierte Unveränderlichkeit
Noe. :) Enums mit veraenderlichem Zustand sind zwar sicherlich ein
Rezept fuer Katzenjammer, nichtsdestotrotz durchaus moeglich.
Ja, gerade gestern drüber gestolpert, als meine Datenbank der Meinung
war, Enum-Objekte wiederherstellen zu müssen, anstatt die im System
vorhandenen einfach weiterzuverwenden.

Meine Klasse sah in etwa so aus:

---
import javax.swing.Icon;
import javax.swing.ImageIcon;

public enum DefaultIcon
implements IconData
{

/* in Wirklichkeit noch ein paar mehr Konstanten */

BOT("bild-bot.png"), DUMMY ("bild-dummy.png");

DefaultIcon(String filename) {
this.filename = filename;
}

private String filename;
private Icon icon;

public Icon getIcon() {
if(icon == null) {
this.icon =
new ImageIcon( DefaultIcon.class.getResource("icons/" +
filename));
}
return icon;
}

}
---
Und jetzt hat db4o beim Abspeichern eines Nutzer-Objektes, welches
dieses Enum als Exemplar-Variable (eigentlich vom Typ IconData) enthält,
offenbar auch das ImageIcon mitgespeichert (anstatt nur eine
Kennzeichnung, welches Enum-Objekt da drin ist), und dann auch
wiederhergestellt - aber irgendwie kaputt, es wurde nämlich in der GUI
nichts gemalt. Da es aber vorhanden war, trat die if-Bedingung nicht ein.

Und als ich dann filename und icon auf transient geändert habe, wurden
Exceptions (beim Laden aus der Datenbank) geworfen, ich kann also nicht
einmal die Datenbank auf eine neue Version meines Enum-Typs upgraden :-(

Jetzt hab ich den Katzenjammer :-(


Paul
Patrick Roemer
2010-12-10 23:38:25 UTC
Permalink
Post by Paul Ebermann
Ja, gerade gestern drüber gestolpert, als meine Datenbank der Meinung
war, Enum-Objekte wiederherstellen zu müssen, anstatt die im System
vorhandenen einfach weiterzuverwenden.
db4o nutzt fuer Enums momentan schlicht den ansonsten eher exotischen
#persistStaticFieldValues()-Modus. Dabei wird das Runtime-Objekt an die
persistente ID gebunden und dann aus dem persistenten Status neu
aktiviert. Wenn man denn persistente statische Felder moechte, ist das
wahrscheinlich das erwartete Verhalten, bei Enums mit veraenderlichem
Zustand bestimmt eher nicht...

Dass der Zustand der Dinger ueberhaupt gespeichert wird, liegt daran,
dass man ggfs. Abfragen "in Enums hinein" haben will, und fuer Queries
braucht db4o nun mal persistenten Zustand.

Ich hab's mal mal im Bugtracker dokumentiert (COR-2103). Ein sauberer
Fix dafuer duerfte aber leider ein groesseres Werk sein, das wuerde auf
Queries hinauslaufen, die nahtlos ueber gemischt persistente/transiente
Objektgraphen gehen. Ob eine einfache aber dreckige Loesung (etwa: fuer
Enums das refresh "abschalten", und stattdessen den aktuellen
Runtime-Zustand persistieren) realistisch ist, muesste man mal schauen.
Post by Paul Ebermann
Und jetzt hat db4o beim Abspeichern eines Nutzer-Objektes, welches
dieses Enum als Exemplar-Variable (eigentlich vom Typ IconData) enthält,
offenbar auch das ImageIcon mitgespeichert (anstatt nur eine
Kennzeichnung, welches Enum-Objekt da drin ist), und dann auch
wiederhergestellt - aber irgendwie kaputt, es wurde nämlich in der GUI
nichts gemalt. Da es aber vorhanden war, trat die if-Bedingung nicht ein.
ImageIcon deklariert so ziemlich alles als transient, was von db4o
respektiert wird. (Bei Plattform-Serialisierung pumpt es schlicht sein
byte[] ad hoc raus.)
Post by Paul Ebermann
Und als ich dann filename und icon auf transient geändert habe, wurden
Exceptions (beim Laden aus der Datenbank) geworfen, ich kann also nicht
einmal die Datenbank auf eine neue Version meines Enum-Typs upgraden :-(
Autsch. :( Das sollte hingegen bestimmt nicht passieren. Ist mit Deinem
Beispiel hier reproduzierbar (NegativeArraySizeException beim Lesen von
Enum#name). COR-2104. Ich schau mal rein.

Viele Gruesse,
Patrick
Paul Ebermann
2010-12-13 14:15:59 UTC
Permalink
Hallo Patrick,

danke für's Reinsehen!
Post by Patrick Roemer
Post by Paul Ebermann
Ja, gerade gestern drüber gestolpert, als meine Datenbank der Meinung
war, Enum-Objekte wiederherstellen zu müssen, anstatt die im System
vorhandenen einfach weiterzuverwenden.
db4o nutzt fuer Enums momentan schlicht den ansonsten eher exotischen
#persistStaticFieldValues()-Modus. Dabei wird das Runtime-Objekt an die
persistente ID gebunden und dann aus dem persistenten Status neu
aktiviert. Wenn man denn persistente statische Felder moechte, ist das
wahrscheinlich das erwartete Verhalten, bei Enums mit veraenderlichem
Zustand bestimmt eher nicht...
Nach der Doku hätte ich eigentlich etwas anderes erwartet:
http://developer.db4o.com/Documentation/Reference/db4o-7.12/java/reference/Content/implementation_strategies/type_handling/static_fields_and_enums/usage_of_static_fields.htm

| This also means that ,if Color.GREEN constant will get another
internal value (RGB(0,255,10)
| instead of RGB(0,255,0) for instance), all the references from the
database will be associated
| with the new value.
Post by Patrick Roemer
Dass der Zustand der Dinger ueberhaupt gespeichert wird, liegt daran,
dass man ggfs. Abfragen "in Enums hinein" haben will, und fuer Queries
braucht db4o nun mal persistenten Zustand.
Ich hab's mal mal im Bugtracker dokumentiert (COR-2103). Ein sauberer
Fix dafuer duerfte aber leider ein groesseres Werk sein, das wuerde auf
Queries hinauslaufen, die nahtlos ueber gemischt persistente/transiente
Objektgraphen gehen. Ob eine einfache aber dreckige Loesung (etwa: fuer
Enums das refresh "abschalten", und stattdessen den aktuellen
Runtime-Zustand persistieren) realistisch ist, muesste man mal schauen.
Mir würde es reichen, wenn das konfigurierbar wäre - meine Abfragen
haben maximal ==/equals bzw. compareTo für die enum-Werte, da brauche
ich keinen Zustand (außer den Namen und eventuell den Index) des
enum-Objektes.

Ich hatte mir zuerst einen Enum-Translator gebaut:
---
private class EnumTranslator<X extends Enum<X>>
implements ObjectConstructor
{
private Class<X> enumClass;
public EnumTranslator(Class<X> enumClass) {
this.enumClass = enumClass;
}
public Object onInstantiate(ObjectContainer container, Object
stored) {
if(stored == null) {
try {
Method m = enumClass.getMethod("values");
Object[] alle = (Object[])m.invoke(null);
Object o = alle[0];
Log.debug("onInstantiate("+stored+") => "+
Arrays.toString(alle) + " => " + o);
return o;
}
catch(NoSuchMethodException ex) {
throw new RuntimeException(ex);
}
catch(IllegalAccessException ex) {
throw new RuntimeException(ex);
}
catch(InvocationTargetException ex) {
throw new RuntimeException(ex);
}
}
Object o = Enum.valueOf(enumClass, (String)stored);
// Log.debug("onInstantiate("+stored+") => " +
o);
return o;
}
public void onActivate(ObjectContainer container, Object
appObject,
Object stored) {
// Noop
}
public Class<?> storedClass() {
return String.class;
}
public Object onStore(ObjectContainer container, Object
appObject) {
return enumClass.cast(appObject).name();
}

} // class EnumTranslator


...
ObjectClass iconClass =
config.common().objectClass(DefaultIcon.class);
iconClass.translate(new
EnumTranslator<DefaultIcon>(DefaultIcon.class));

---
Aber das gab auch Probleme beim Umstellen der Datenbank auf die
neue Version.
Wie baut man so etwas ein? Mit zwei Datenbanken, und verschiedenen
Konfigurationen und Kopieren aller Objekte? Oder geht das mittels
Defragment? (Ich werde mal die Doku dazu lesen.)


Der "if (stored == null)"-Block sollte im Normal-Betrieb ja nicht
auftreten, aber
kam eben doch zustande, als ich die Objekte der alten Version geladen
habe.
Das führte dann irgendwie dazu, dass eines der enum-Objekte (genauer
values()[0])
seinen name() geändert hat.
Post by Patrick Roemer
Post by Paul Ebermann
Und als ich dann filename und icon auf transient geändert habe, wurden
Exceptions (beim Laden aus der Datenbank) geworfen, ich kann also nicht
einmal die Datenbank auf eine neue Version meines Enum-Typs upgraden :-(
Autsch. :( Das sollte hingegen bestimmt nicht passieren. Ist mit Deinem
Beispiel hier reproduzierbar (NegativeArraySizeException beim Lesen von
Enum#name). COR-2104. Ich schau mal rein.
Danke, das spart mir, selbst einen Bugreport zu basteln.

Als Workaround dient es wahrscheinlich, das erst einmal als nicht-
transient
zu lassen, und die Felder nach dem Laden manuell auf null zu setzen.


Paul

Bernd Eckenfels
2010-12-04 20:31:02 UTC
Permalink
Post by Johannes Lichtenberger
enum XPathState {
private enum StateType {
wieso hast du denn 2?

Gruss
Bernd
Johannes Lichtenberger
2010-12-04 21:17:00 UTC
Permalink
Post by Bernd Eckenfels
Post by Johannes Lichtenberger
enum XPathState {
private enum StateType {
wieso hast du denn 2?
Keine Ahnung, nachts Effective Java gelesen und den kleinen oder
größeren Unterschied zu meinem Beispiel nicht bemerkt, ist aber schon
geändert.

Die andere Anmerkung hat sich dann auch erledigt, sofern halt nicht alle
Methoden im enum selbst verfügbar sind ist ein switch also ohne Weiteres ok.

Viele Grüße,
Johannes
Lesen Sie weiter auf narkive:
Loading...