Teil 2: Verwendung von Tabellen und Formeln
Verwendung von Tabellen
In diesem Kapitel erweitern wir das Modell um Tabellen zur Abbildung der Tarifzonen und Beitragssätze und programmieren die Ermittlung der für einen Vertrag gültigen Tarifzone.
Tarifzonentabelle
Aufgrund der in Deutschland regional unterschiedlichen Schadenswahrscheinlichkeit durch Einbruchdiebstahl unterscheiden Versicherungsunternehmen in der Hausratversicherung zwischen unterschiedlichen Tarifzonen. Hierzu verwenden Versicherer eine Tabelle, mit der einem Postleitzahlenbereich eine Tarifzone zugeordnet ist. Im Tutorial nutzen wir folgende Tabelle die später noch benötigt wird:
Plz-von | Plz-bis | Tarifzone |
---|---|---|
17235 |
17237 |
II |
30159 |
45549 |
III |
59174 |
59199 |
IV |
47051 |
47279 |
V |
63065 |
63075 |
VI |
… |
… |
… |
Für alle Postleitzahlen, die in keinen der Bereiche fallen, gilt die Tarifzone I.
Faktor-IPS unterscheidet zwischen der Definition der Tabellenstruktur und dem Tabelleninhalt. Die Tabellenstruktur wird als Teil des Modells angelegt. Der Tabelleninhalt kann abhängig vom Inhalt und der Verantwortung für die Pflege der Daten sowohl als Teil des Modells oder als Teil der Produktdefinition verwaltet werden. Zu einer Tabellenstruktur kann es dabei mehrere Tabelleninhalte geben. Dies entspricht dem Konzept von Tabellenpartitionen in relationalen Datenbankmanagementsystemen.
Legen wir zunächst die Tabellenstruktur für die Ermittlung der Tarifzonen an. Hierzu wechseln Sie zunächst zurück in die Java-Perspektive. Im Projekt Hausratmodell unter dem Ordner „model“
markieren Sie den Ordner „hausrat“
und klicken dann in der Toolbar auf . Die Tabellenstruktur nennen Sie „Tarifzonentabelle“
und klicken Finish.
Als Tabellentyp wählen Sie den Typ Single Content, da es für diese Struktur nur einen Inhalt geben soll. Nun legen wir zunächst die Spalten der Tabelle an. Alle drei Spalten (plzVon, plzBis, tarifzone) sind vom Datentyp String.
Interessant wird es jetzt bei der Definition des Postleitzahlenbereiches: Die von uns angelegte Tabellenstruktur dient uns letztendlich dazu, die Funktion (im mathematischen Sinne) tarifzone → plz
abzubilden. Allein mit der Spaltendefinition und einem möglichen UniqueKey ist diese Semantik allerdings nicht abbildbar. In Faktor-IPS gibt es aus diesem Grund die Möglichkeit zu modellieren, dass die Spalten (oder eine Spalte) einen Bereich darstellen. Legen Sie jetzt einen neuen Bereich an (Bereiche ► Neu). Da die Tabelle Von- und Bis-Spalten enthält, wählen Sie als Typ Two Column Range. Als „Parameter Name“
geben Sie jetzt „plz“
ein und ordnen noch die beiden Spalten plzVon und plzBis zu.
Jetzt legen Sie noch einen neuen UniqueKey an (Indices ► Neu). Dem UniqueKey ordnen Sie jetzt nicht die einzelnen Spalten plzVon und plzBis zu, sondern den Bereich und speichern dann die Strukturbeschreibung.
Faktor-IPS hat nun für die Tabellenstruktur zwei neue Klassen im Source folder „src“
unter dem Package org.faktorips.tutorial.model.hausrat
generiert.
Die Klasse TarifzonentabelleRow
repräsentiert eine Zeile der Tabelle und enthält für jede Spalte eine Membervariable mit entsprechenden Zugriffsmethoden. Die Klasse Tarifzonentabelle
repräsentiert den Tabelleninhalt. Neben Methoden, um den Tabelleninhalt aus XML zu initialisieren, wurde aus dem UniqueKey eine Methode zum Suchen einer Zeile generiert:
public TarifzonentabelleRow findRow(String plz) {
// Details der Implementierung sind hier ausgelassen
}
Nutzen wir jetzt diese Klasse, um die Ermittlung der Tarifzone für den Hausratvertrag zu implementieren. Die Tarifzone ist eine abgeleitete Eigenschaft des Hausratvertrags und in der Klasse HausratVertrag
gibt es somit die Methode getTarifzone()
. Diese hatten wir bereits wie folgt implementiert:
public String getTarifzone() {
// begin-user-code
// TODO wird spaeter anhand einer Tarifzonentabelle ermittelt
return "I";
// end-user-code
}
Nun ermitteln wir die Tarifzonen anhand der Postleitzahl aus der gerade angelegten Tabelle wie folgt:
public String getTarifzone() {
// begin-user-code
if (plz==null) {
return null;
}
IRuntimeRepository repository = getHausratProdukt().getRepository();
Tarifzonentabelle tabelle = Tarifzonentabelle.getInstance(repository);
TarifzonentabelleRow row = tabelle.findRow(plz);
if (row==null) {
return "I";
}
return row.getTarifzone();
// end-user-code
}
Es bedarf an dieser Stelle noch einer Erläuterung, wie man an die Instanz der Tabelle herankommt. Da es zur Tarifzonentabelle nur einen Inhalt gibt, hat die Klasse Tarifzonentabelle
eine getInstance
() Methode, die diesen Inhalt zurück liefert. Als Parameter bekommt diese Methode das RuntimeRepository, welches zur Laufzeit Zugriff auf die Produktdaten inklusive der Tabelleninhalte gibt. An dieses kommen wir leicht über das Produkt, auf dem der Vertrag basiert [1].
1 Das Übergeben des RuntimeRepositories in die Methode getInstance()
hat den Vorteil, dass das konkrete Repository in Testfällen leicht ausgetauscht werden kann.
Jetzt legen wir noch den Tabelleninhalt an. Die Zuordnung der Postleitzahlen zu den Tarifzonen soll von der Fachabteilung gepflegt werden. Zur Strukturierung fügen Sie noch ein neues IPS Package Tabellen
in dem Projekt Hausratprodukte ein. Danach markieren Sie das neue Package und klicken in der Toolbar auf . Wählen Sie in dem Dialog die Tarifzonentabelle als Struktur aus. Als Namen für den Tabelleninhalt übernehmen Sie den Namen Tarifzonentabelle und klicken Finish. In dem Editor können Sie nun die oben beispielhaft aufgeführten Zeilen erfassen. Die Projektstruktur im Produktdefinitions-Explorer sollte danach wie folgt aussehen:
Zum Schluss testen wir noch die Ermittlung der Tarifzone. Hierzu erweitern wir den im ersten Teil des Tutorials angelegten JUnit Test „TutorialTest“ um die folgende Testmethode [2].
2 Im Tutorial Softwaretests mit Faktor-IPS wird u.a. beschrieben, wie man diesen Test mit Faktor-IPS Hilfsmitteln komfortabel erzeugen und durchführen kann.
@Test
public void testGetTarifzone() {
// Erzeugen eines Hausratvertrags mit der Factorymethode des Produktes
HausratVertrag vertrag = kompaktProdukt.createHausratVertrag();
vertrag.setPlz("45525");
assertEquals("III", vertrag.getTarifzone());
}
Beitragstabelle
Der Beitragssatz für die Grunddeckung der Hausratversicherung soll anhand der Tarifzone aus einer Tariftabelle ermittelt werden. Dabei sollen für die beiden Produkte unterschiedliche Beitragssätze gemäß den folgenden Tabellen gelten.
Tarifzone | Beitragssatz |
---|---|
I |
0.80 |
II |
1.00 |
III |
1.44 |
IV |
1.70 |
V |
2.00 |
VI |
2.20 |
Tarifzone | Beitragssatz |
---|---|
I |
0.60 |
II |
0.80 |
III |
1.21 |
IV |
1.50 |
V |
1.80 |
VI |
2.00 |
Die Daten für die unterschiedlichen Produkte werden häufig in einer Tabelle zusammengefasst, in der es dann noch eine Spalte „ProduktID“ gibt. In Faktor-IPS kann man aber auch zu einer Tabellenstruktur mehrere Inhalte anlegen und den Zusammenhang zu den Produktbausteinen explizit modellieren!
Legen Sie hierfür eine Tabellenstruktur TariftabelleHausrat mit den beiden Spalten Tarifzone (String) und Beitragssatz (Decimal) an. Definieren Sie einen UnqiueKey auf die Spalte Tarifzone. Als Tabellentyp wählen Sie diesmal Multiple Contents aus, da wir für jedes Produkt einen eigenen Tabelleninhalt anlegen wollen.
Erzeugen Sie nun für die Produkte HR-Optimal und HR-Kompakt (bzw. genauer für deren Grunddeckungstypen) jeweils einen Tabelleninhalt mit dem Namen „Tariftabelle Optimal 2019-07“ und „Tariftabelle Kompakt 2019-07“ [3].
3 Die Endung „2019-07“ sollten Sie dabei entsprechend des von Ihnen verwendeten Wirksamkeitsdatums anpassen.
Das folgende Diagramm zeigt den Zusammenhang zwischen der Klasse Grunddeckungstyp und der Tabellenstruktur TariftabelleHausrat und die entsprechenden Objektinstanzen.
Um den Zusammenhang zwischen Tabellen und Produkten in Faktor-IPS zu definieren, öffnen Sie die Klasse HausratGrunddeckungstyp. Auf der zweiten Seite „Verhalten“ im Editor [4] im Abschnitt Table Usages (Verwendete Tabellen) können Sie eine neue Tabellenverwendung definieren. Hierzu klicken Sie auf den New Button im Abschnitt „Verwendete Tabellen“. Geben Sie „tariftabelle“ als Rollennamen ein, wählen Sie „Tabelleninhalt erforderlich“ aus und fügen Sie „Tabellenstruktur“ TariftabelleHausrat hinzu, laut nachfolgender Abbildung:
4 Vorausgesetzt, Sie haben in den Preferences eingestellt, dass die Editoren zwei Abschnitte pro Seite verwenden sollen.
An dieser Stelle können Sie auch mehrere Tabellenstrukturen zuordnen, da im Laufe der Zeit z.B. neue Tarifierungsmerkmale hinzukommen und so unter der Rolle Tariftabelle unterschiedliche Tabellenstrukturen möglich sein können. Haken Sie noch die Checkbox Table content required an, da für jeden Grunddeckungstypen eine Tariftabelle angegeben werden muss, dann schließen Sie den Dialog und speichern.
Nun können wir die Tabelleninhalte den Grunddeckungstypen zuordnen. Öffnen Sie zunächst HRD-Grunddeckung-Kompakt 2019-07. Den Dialog, der Sie darauf hinweist, dass die Tariftabelle noch nicht zugeordnet ist, bestätigen Sie mit Fix. In dem Abschnitt Tabellen und Berechnungsvorschriften können Sie nun die Tariftabelle für HR-Kompakt zuordnen und dann speichern.
Analog verfahren Sie für HR-Optimal.
Zum Schluss dieses Kapitels werfen wir noch einen Blick auf den generierten Sourcecode. In der Klasse HausratGrunddeckungstyp gibt es eine Methode, um den zugeordneten Tabelleninhalt zu erhalten:
public TariftabelleHausrat getTariftabelle() {
if (tariftabelleName == null) {
return null;
}
return (TariftabelleHausrat) getRepository().getTable(tariftabelleName);
}
Da auch die Findermethoden an der Tabelle generiert sind, lässt sich so mit sehr wenigen Zeilen Sourcecode ein effizienter Zugriff auf eine Tabelle realisieren.