s05 – Enumerations (Aufzählungen)

 

Enumerations sind Aufzählungen, mit denen man eine Reihe von Konstanten übersichtlicher verwalten kann. Es gibt zwei Möglichkeiten, Enums zu nutzen. Diese sollen hier in aufsteigender Schwierigkeit vorgestellt werden.

Interface Antipattern

Die erste Möglichkeit, Enums zu implementieren, sind Java Interfaces. Diese werden normalerweise eher verwendet, um Verhaltensweisen festzulegen, während sie in diesem Fall eher Namespaces verwalten. Das ist der Grund, aus dem man von einem Antipattern spricht.

Ein Java-Interface kann statische Konstanten (Variablen vom typ final) enthalten:

public interface Enum1
{
	public static final int LINKS  = 1;
	public static final int RECHTS = 2;
	public static final int HOCH   = 3;
	public static final int RUNTER = 1;
}

Dieses Interface kann auf zwei Wegen benutzt werden. Die erste Möglichkeit ist, das Enum mit der vollen Bezeichnung zu nutzen:

if(iZahl == Enum1.RECHTS)
	// nach rechts bewegen

Oder eine Klasse, die das Enum benutzen soll, kann das Interface implementieren:

class Enum1Nutzer implements Enum1
{
	...
	void bewegen()
	{
		if (iZahl == HOCH)
			// nach oben bewegen
	}
}

Diese Möglichkeit, Enums zu benutzen, ist sehr einfach. Es gibt aber verschiedene Probleme, vor allem die Nutzerfreundlichkeit.
Wenn im Programm ein Wert vom Nutzer entgegengenommen wird, muss dies in etwa so geschehen:

System.out.println("In welche Richtung möchten Sie sich bewegen?);

// Eingaberoutine...

switch iRichtung:
{
	case Enum1.LINKS:
		// nach links bewegen
	case Enum1.RECHTS:
		// nach rechts bewegen
	case Enum1.HOCH:
		// nach oben bewegen
	case Enum1.RUNTER:
		// nach unten bewegen
}

Wenn der Nutzer nun weiß, dass er eine 3 eingeben muss, um sich nach oben zu bewegen, ist dies kein Problem, allerdings erfordert solch ein Programm eine gute Dokumentation und eine gute Fehlerbehandlung (der Nutzer könnte 7 eingeben, ohne dass der Fehler sofort bemerkt wird).

Ein weiteres Problem mit der Verwendung von Interfaces als Enums ist die explizite Aufzählung aller Werte in der Deklaration des Interfaces. Wenn ein neuer Wert hinzukommt (weil man sich etwa auch schräg bewegen können soll) muss dann nicht nur das Interface geändert werden, sondern auch alle switch-Blöcke, in denen das Enum verwendet wurde.

Enums als Klassen

Da wir nun die Schwächen der Verwendung reiner Interfaces als Enums kennen, werden wir versuchen, eine Aufzählung möglichst geschickt als Klasse zu implementieren

public class Enum2
{
	public static final EnumVer2 LINKS  = new Enum2();
	public static final EnumVer2 RECHTS = new Enum2();
	public static final EnumVer2 HOCH   = new Enum2();
	public static final EnumVer2 RUNTER = new Enum2();
}

Die Klasse enthält also Instanzen von sich selbst. Diese haben keine Attribute und sind daher im Prinzip alle gleich. Sie unterscheiden sich nur durch ihre Adresse im Arbeitsspeicher. Das ist aber auch schon genug, da die Instanzen final sind uns sich ihre Adresse während des Programmablaufes nicht ändert. Die Adresse ist daher ein eindeutiges Identifizierungsmerkmal.
Die Klasse kann wie folgt verwendet werden:

void bewegen(Enum2 richtung)
{
	if(richtung == Enum2.LINKS)
		// nach links bewegen
	else if(richtung == Enum2.RECHTS)
		// nach rechts bewegen
	else if(richtung == Enum2.HOCH)
		// nach oben bewegen
	else if(richtung == Enum2.RUNTER)
		// nach unten bewegen
}

Die Methode bewegen kann nun nicht mehr mit einem Integer als Parameter aufgerufen werden, sondern nur noch mit einem Objekt des Typs Enum2, wodurch eine größere Sicherheit gegeben ist.

Um die Klasse zu perfektionieren, sollte der Konstruktor private sein, damit jemand, dem man den Programmtext weitergibt, nicht aus Unwissen neue Instanzen erzeugen kann. Weiterhin sollten Helferfunktionen implementiert werden, um zum Beispiel einem String direkt eine Richtung zuordnen zu können.

Ähnliche Artikel

Kommentar verfassen