8. Anwendungsübung – [Steuerberechnung] mit einer mehrschichtigen Architektur
![]() |
Hier greifen wir die in Abschnitt 4.1 beschriebene Übung wieder auf. Wir beginnen mit der in Abschnitt 4.3 beschriebenen Textdatei-Version. Um dieses Beispiel mit Objekten zu bearbeiten, verwenden wir eine dreistufige Architektur:
![]() |
- Die [DAO]-Schicht (Data Access Object) übernimmt den Datenzugriff. Im Folgenden befinden sich diese Daten zunächst in einer Textdatei, später in einer MySQL-Datenbank;
- Die [Business]-Schicht ist für die Geschäftslogik zuständig, in diesem Fall für die Steuerberechnung. Sie verarbeitet keine Daten. Diese Daten können aus zwei Quellen stammen:
- der [DAO]-Schicht für persistente Daten;
- die [Konsole]-Schicht für vom Benutzer bereitgestellte Daten.
- Die [Console]-Schicht ist für die Interaktion mit dem Benutzer zuständig.
Im Folgenden werden die [DAO]- und die [Business]-Schicht jeweils mithilfe einer Klasse implementiert. Die [Console]-Schicht wird durch das Hauptprogramm implementiert.
Wir gehen davon aus, dass alle Implementierungen der [dao]-Schicht die Methode getData() bereitstellen, die ein Tupel mit drei Elementen (limits, coeffR, coeffN) zurückgibt – die drei Datenarrays, die zur Berechnung der Steuer benötigt werden. In anderen Sprachen wird dies als Schnittstelle bezeichnet. Eine Schnittstelle definiert Methoden (hier getData), über die Klassen verfügen müssen, die diese Schnittstelle implementieren.
Die [business]-Schicht wird durch eine Klasse implementiert, deren Konstruktor eine Referenz auf die [dao]-Schicht als Parameter entgegennimmt, wodurch die Kommunikation zwischen den beiden Schichten sichergestellt wird.
8.1. Die [DAO]-Schicht
Wir werden die verschiedenen für die Anwendung erforderlichen Klassen in einer einzigen Datei, impots.py, zusammenfassen. Die Objekte in dieser Datei werden dann in die Skripte importiert, die sie benötigen.
Wir beginnen mit dem Fall, in dem sich die Daten in einer Textdatei befinden, wie im Beispiel in Abschnitt 4.3.
![]() |
Der Code für die Klasse [ ImpotsFile] (impots.py), die die [DAO]-Schicht implementiert, lautet wie folgt:
Anmerkungen:
- Zeilen 7–8: Wir definieren eine Klasse „ImpotsError“, die von der Klasse „Exception“ abgeleitet ist. Diese Klasse fügt der Klasse „Exception“ nichts hinzu. Wir verwenden sie ausschließlich, um eine benutzerdefinierte Ausnahmeklasse zu haben. Diese Klasse könnte später erweitert werden;
- Zeilen 11–18: eine Klasse mit Hilfsmethoden. Hier entfernt die Methode
*cutNewLineChar*alle Zeilenumbruchzeichen aus einer Zeichenkette; - Zeile 25: Beim Öffnen der Datei kann die Ausnahme „IOError“ ausgelöst werden;
- Zeilen 32, 39, 46: Die benutzerdefinierte Ausnahme „ImpotsError“ wird ausgelöst;
- Der Code ähnelt dem im Beispiel in Abschnitt 4.3 behandelten.
8.2. Die [Business]-Schicht
![]() |
Die Klasse [ ImpotsMetier] (impots.py), die die [Geschäftsschicht] implementiert, sieht wie folgt aus:
class ImpotsMetier:
# constructeur
# on récupère un pointeur sur la couche [dao]
def __init__(self, dao):
self.dao=dao
# calcul de l'impôt
# --------------------------------------------------------------------------
def calculer(self,marie,enfants,salaire):
# marié : oui, non
# enfants : nombre d'enfants
# salaire : salaire annuel
# on demande à la couche [dao] les données nécessaires au calcul
(limites, coeffR, coeffN)=self.dao.getData()
# nombre de parts
marie=marie.lower()
if(marie=="oui"):
nbParts=float(enfants)/2+2
else:
nbParts=float(enfants)/2+1
# une 1/2 part de plus si au moins 3 enfants
if enfants>=3:
nbParts+=0.5
# revenu imposable
revenuImposable=0.72*salaire
# quotient familial
quotient=revenuImposable/nbParts
# est mis à la fin du tableau limites pour arrêter la boucle qui suit
limites[len(limites)-1]=quotient
# calcul de l'impôt
i=0
while quotient>limites[i] :
i=i+1
# du fait qu'on a placé quotient à la fin du tableau limites, la boucle précédente
# ne peut déborder du tableau limites
# maintenant on peut calculer l'impôt
return math.floor(revenuImposable*(float)(coeffR[i])-nbParts*(float)(coeffN[i]))
Anmerkungen:
- Zeilen 5–6: Der Klassenkonstruktor erhält eine Referenz auf die [dao]-Schicht als Parameter;
- Zeile 16: Wir verwenden die Methode getData der [dao]-Schicht, um die für die Berechnung der Steuer erforderlichen Daten abzurufen;
- Der Rest des Codes entspricht dem im Beispiel in Abschnitt 4.3 behandelten.
8.3. Die [console]-Schicht
![]() |
Das Skript zur Implementierung der [console]-Schicht (impots-03) lautet wie folgt:
Hinweise:
- Zeile 4: Wir importieren alle Objekte aus der Datei impots.py, die die Klassendefinitionen enthält. Sobald dies geschehen ist, können wir diese Objekte so verwenden, als befänden sie sich in derselben Datei wie das Skript;
- Zeilen 17–21: Wir instanziieren sowohl die [dao]-Schicht als auch die [business]-Schicht und behandeln dabei mögliche Ausnahmen;
- Zeile 18: Wir instanziieren die [dao]-Schicht und anschließend die [business]-Schicht. Wir speichern die Referenz auf die [business]-Schicht;
- Zeile 19: Wir behandeln die beiden Ausnahmen, die auftreten können;
- Der Rest des Codes ähnelt dem im Beispiel in Abschnitt 4.3 behandelten.
8.4. Ergebnisse
Die gleichen wie die bereits in den Versionen mit Arrays und Dateien erzielten.
Die Datendatei impots.txt:
12620:13190:15640:24740:31810:39970:48360:55790:92970:127860:151250:172040:195000:0
0:0.05:0.1:0.15:0.2:0.25:0.3:0.35:0.4:0.45:0.5:0.55:0.6:0.65
0:631:1290.5:2072.5:3309.5:4900:6898.5:9316.5:12106:16754.5:23147.5:30710:39312:49062
Die Datendatei data.txt:
Die Datei „results.txt“ mit den Ergebnissen:




