Datentypen & Aufzählungen in Faktor-IPS

Verwendung von Ableitungen

In Applikationen gibt es häufig Aspekte, die für alle Aufzählungen gleich funktionieren, zum Beispiel die Anzeige der Werte einer Aufzählung in einer Listbox. Um dies umzusetzen ist es hilfreich, wenn alle Aufzählungen ein einheitliches Interface implementieren bzw. von einer gemeinsamen Basisklasse ableiten. Für diese Aspekte ist es dabei in der Regel nicht relevant, ob die Werte Teil des Modells oder Teil der Konfiguration sind. Beide Arten von Aufzählungen sollten gleich behandelt werden können.

Wir erweitern also unsere bisherigen Beispiele um einen Basistyp, den wir EnumValue nennen. Dies zeigt das folgende Diagramm.

Ableitungshierarchie der Aufzählungstypen
Figure 1. Ableitungshierarchie der Aufzählungstypen

Legen Sie nun bitte den Aufzählungstyp EnumValue gemäß der folgenden Abbildung an:

Ausgefüllter Wizard zum Anlegen des abstrakten Aufzählungstypen EnumValue
Figure 2. Ausgefüllter Wizard zum Anlegen des abstrakten Aufzählungstypen EnumValue

Achten Sie darauf direkt die Checkbox Abstract anzuhaken. Wenn Sie die Abstrakt-Eigenschaft nachträglich im Editor ändern, müssen Sie vorher den generierten Sourcecode für EnumValue löschen. Das von Faktor-IPS verwendete Framework zum Mergen 13 des Sourcecodes kann mit dieser Änderung nicht umgehen.

Faktor-IPS generiert für den abstrakten Aufzählungstyp das folgende Interface:

public interface EnumValue {

	@IpsEnumAttribute(name = "id", identifier = true, unique = true)
	@IpsGenerated
	public String getId();

	@IpsEnumAttribute(name = "name", unique = true, displayName = true)
	@IpsGenerated
	public String getName();
}

Die Generierung eines Interfaces ist erforderlich, da Java-Enums lediglich Interfaces implementieren können, aber nicht von anderen Enums abgeleitet werden können.

Nun müssen wir noch in den bestehenden Aufzählungstypen EnumValue als Supertyp eintragen. Öffnen Sie zunächst den Editor für die Zahlweise. Im Abschnitt General Information können Sie den Supertyp angeben. Bei den beiden Attributen id und name müssen wir nun noch markieren, dass die Definition aus dem Supertyp geerbt wird. Hierzu öffnen Sie jeweils den Dialog zum Bearbeiten eines Attributes über Bearbeiten…​ und haken die Checkbox Aus Supertyp-Hierarchie geerbt an.

Markierung eines Attributes als geerbt
Figure 3. Markierung eines Attributes als geerbt

Nachdem Sie beide Attribute als geerbt markiert und gespeichert haben, implementiert der generierte Java-Enum Zahlweise das Interface EnumValue. Der Rest des Codes für Zahlweise bleibt unverändert.

public enum Zahlweise implements EnumValue {
    ... wie bisher
}

Leiten Sie nun analog den Aufzählungstyp Parkplatzart von EnumValue ab. Danach implementiert nun auch die Java-Klasse Parkplatzart das Interface EnumValue.

public final class Parkplatzart implements EnumValue, Serializable {
    .. wie bisher
}

Nun können wir Aspekte, die für alle Aufzählungen gleich sind, unter Verwendung des Interfaces EnumValue implementieren. Der folgende Codeabschnitt führt das Beispiel zur Ausgabe der Parkplatzarten fort und gibt nun auch die Zahlweisen auf der Konsole aus. Die Ausgabe der Werte auf der Konsole ist in eine Methode printValues(…​) ausgelagert worden.

public static void main(String[] args) {
    // Repository erzeugen
    IRuntimeRepository repository = ClassloaderRuntimeRepository.create(
            "org/faktorips/sample/model/internal/faktorips-repository-toc.xml");

    // Parkplatzarten aus dem Repository abfragen ...
    List<Parkplatzart> arten = repository.getEnumValues(Parkplatzart.class);

    // ... und auf der Konsole ausgeben
    printValues(arten);

    // Zahlweisen auf der Konsole ausgeben
    List<Zahlweise> zahlweisen = Arrays.asList(Zahlweise.values());
    printValues(zahlweisen);
}

public static void printValues(List<? extends AbstractEnumValue> values) {
    for (AbstractEnumValue value : values) {
        System.out.println(value.toString());
    }
}

Das nachträgliche Einrichten der Ableitungsbeziehung ist etwas lästig, da man die Attribute nachträglich als abgeleitet kennzeichnen muss. In der Regel legt man aber weitere Aufzählungstypen auf Basis des bestehenden EnumValue an. Gibt man den Supertyp direkt im Wizard zum Erzeugen eines neuen Aufzählungstypen an, dann werden auch die entsprechenden Attribute aus dem Supertyp erzeugt.