600 likes | 824 Views
Gliederung. Komplexe(re)s Beispiel: Steuer v.Beschäftigte(n) Aspekte des Software Engineering (Anforderungsanalyse) SW- Entwurf --> Klassifikationshierarchie Implementierung --> Klassenhierarchie Implementierungsaspekte Klassenhierarchie - virtual/rein virtual
E N D
Gliederung • Komplexe(re)s Beispiel: Steuer v.Beschäftigte(n) • Aspekte des Software Engineering • (Anforderungsanalyse) • SW- Entwurf --> Klassifikationshierarchie • Implementierung --> Klassenhierarchie • Implementierungsaspekte • Klassenhierarchie - virtual/rein virtual • inline - Wiederholung Liste - rand() • (Vorteil des OO-Ansatzes) • Erweiterung • Nachteil von alternativem Ansatz
Beschäftigte • Grobklassifikation: • Angestellte: festbesoldet • Arbeiter: Entlohnung nach Arbeitsstunden • Steuern: • Freibetrag: (abhängig von Position) • Einheitlicher Steuersatz: 45%
Beschäftigte (Forts.) • also: • Steuer = ((Gehalt - Freibetrag)*45)/100, • Freibetrag ergibt sich aus Basisfreibetrag + Zusatzfreibetrag, • Basisfreibetrag für alle: 500 DM
Beschäftigte (Forts.) • Angestellte: • B1: 4000 DM, Zusatzfreibetrag: 200 DM, • B2: 6000 DM, Zusatzfreibetrag: 400 DM. • Arbeiter: • A1: Stundenlohn: 20 DM • A2: Stundenlohn: 30 DM • Zusatzfreibetrag für alle: 100 DM.
Aufgabe • Realisierung dieser Hierarchie • Implementierung auf Grundlage der Modellierung --> einige neue Gesichtspunkte und Ideen. • Berechnungen: • Gehaltssumme • Summe anderer Ausgaben. • Erweiterung der Hierarchie • um B3
Programm-Entwurf • Klassifikationshierarchie angemessen berücksichtigen: • Vererbung folgt der (Modellierungs-)Hierarchie • In der Hierarchie angegebene Attribute etc. an der richtigen Stelle darstellen • Attribute und Methoden "so hoch wie mög- lich im Baum" anbringen.
Konsequenzen • Jedem Knoten im Kassifikationsbaum entspricht eine Klasse. • Die Relation IstSohnVon in der Klassifikationshierarchie wird übersetzt in ErbtVon in der Klassenhierarchie.
Programm-Entwurf (Forts.) • Abstrakte Methoden da, wo • der Name bereits bekannt sein sollte, • der Name schon verwendet werden kann, • der Code noch nicht angegeben werden kann oder soll.
wichtige Kategorie auch in der Softwaretechnik Programm-Entwurf (Forts.) • Zugriffsspezifikationen angemessen berücksichtigen: • Sie werden in der (Modell-)Hierarchie nicht dargestellt. • Hier hilft gesunder Menschenverstand.
rein virtuelle Funktionen Die Klasse Beschaeftigter als Wurzel class Beschaeftigter { private: char * Name; protected: static const int BasisFreibetrag = 500;//* virtual int DerZusatzfreibetrag() = 0; public: Beschaeftigter(char *); virtual int Gehalt() = 0; int Freibetrag(); int Steuer(); char * DerName(); virtual void Druck (); }; * In Borland so nicht: "Mag der Compiler nicht". Konstante
Konstruktor/ Druck Beschaeftigter :: Beschaeftigter(char * t) { Name = new char[strlen(t)]; strcpy(Name, t); } void Beschaeftigter::Druck() { cout << "Name: "<< DerName() << "\t\tGehalt: "<< Gehalt() << endl; }
Berechnung der Steuer • Bemerkenswert: • Gehalt ist rein virtuell • der Code ist also an dieser Stelle nicht bekannt, • er wird erst später klassenspezifisch nachgetragen. • Steuern sollten (numerisch) positiv sein!
Beachten Sie: rein virtuelle Methoden Weitere Methoden • Ausgabe des Namens • Berechnung des Freibetrags • Berechnung der Steuer char * Beschaeftigter::DerName() { return Name;} int Beschaeftigter ::Freibetrag() { return BasisFreibetrag + DerZusatzfreibetrag();} int Beschaeftigter::Steuer() { int SteuerGehalt = Gehalt() - Freibetrag(); return (SteuerGehalt > 0 ? (SteuerGehalt*45)/100 : 0) ;}
Nächste Ebene • Implementiert werden sollten • die Klasse Angestellter, • die Klasse Arbeiter. • Angestellter: keine besonderen Angaben • Arbeiter: schon komplizierter.
Die Klasse der Angestellten class Angestellter : public Beschaeftigter { protected: int FestGehalt; public: Angestellter(char * t): Beschaeftigter (t) {} }; Konstruktor wird mit dem Code angegeben, der ihn implementiert (inline-Formulierung)
Einschub zu : inline • Zum Abarbeiten einer Methode: • Konstruktion eines activation record mit • Werten der aktuellen Parameter, • Werten lokaler Variablen, • Rückgabewert, Rücksprungadresse etc. • Beim Aufruf der Methode: • Aktivierung des activation record auf dem Laufzeitstack • Rücksprung an die Stelle des Aufrufs, wenn der Aufruf abgearbeitet ist.
Einschub: inline (Forts.) • Methodenaufruf zeitintensiv • -> bei einfachen Methoden: Verwaltungsaufwand höher als der Aufwand für die Berechnung. • Alternative: inline • Spare mir den Aufwand mit dem activation record, • kopiere dafür den Code für die Methode direkt an die Stelle im Aufruf.
Einschub: inline (Forts.) • •inline-Formulierung sollte (nur) in einfachen Fällen benutzt werden: Vereinfacht die Formulierung erheblich, wird also hier i.f. (stillschweigend) verwendet. • • Ist Frage der Implementierung Ändert also nicht die Wirkung (Semantik) der Funktion.
Angestellter B1 • • Stellen keine abstrakte Klasse dar: • Es sollen Objekte dieses Typs erzeugt werden, • alle Angaben sind vorhanden. • • Konsequenz: • Die rein virtuellen Methoden, die noch nicht implementiert wurden, müssen in dieser Klasse realisiert werden: • Gehalt • DerZusatzfreibetrag
Klassendefinition class AngestellterB1 : public Angestellter { public: AngestellterB1(char * t): Angestellter(t) {FestGehalt = 4000;} int Gehalt() {return FestGehalt;} int DerZusatzfreibetrag() {return 200;} void Druck () { cout<< " Angestellter B1\t" ; Beschaeftigter::Druck(); }; };
Die Klasse Arbeiter • Rein virtuelle Methoden • DerZusatzfreibetrag, Gehalt • hier implementierbar. • Dazu Einführung einer rein virtuellen Methode DerStundenlohn • gibt den Stundenlohn für die jeweilige Klasse an • verwendbar, ohne daß der Wert dafür bekannt.
Die Klasse Arbeiter (Forts.) class Arbeiter: public Beschaeftigter { protected: int StundenZahl; int DerZusatzfreibetrag() {return 100;} public: Arbeiter(char * t):Beschaeftigter(t) {} void SetzeStunden(int v) {StundenZahl = v;} int DieStundenZahl() {return StundenZahl;} virtual int DerStundenlohn() = 0; int Gehalt() { return DerStundenlohn()*DieStundenZahl();} };
ArbeiterA1 • Die Klasse ist nicht abstrakt. • Vorgehen wie oben für AngestellterB1: • muß die bislang virtuell gebliebenen Methoden definieren
ArbeiterA1 (Forts.) class ArbeiterA1: public Arbeiter { public: ArbeiterA1(char *, int); int DerStundenlohn() { return 20; } void Druck () { cout<< " Arbeiter A1\t\t" ; Beschaeftigter::Druck(); }; }; ArbeiterA1:: ArbeiterA1(char * t, int w): Arbeiter(t) { StundenZahl = w; }
Andere Klassen • Definition der anderen Klassen: • AngestellterB2 • ArbeiterA2 völlig analog zu den angegebenen Definitionen, wird daher hier nicht wiederholt.
Zusammenfassung • Konstruktion einer Klassifikationshierarchie aus einer Beschreibung • Daten • Verhalten, d.h. Methoden • Umsetzung in eine Klassenhierarchie • Überlegung, wo Komponenten (Methoden, Attribute) angebracht werden,
Zusammenfassung (Forts.) • Analyse, an welcher Stelle welche Methode benötigt wird, • Überlegung, an welcher Stelle welche Methode definiert werden kann • d.h.auch: Realisierung abstrakter Klassen/ [rein] virtueller Methoden. • Technisch: • Einführung von inline-Code.
Buchhalteraufgabe • Aufgabe: • Bestimme, was monatlich an Gehältern, Steuern und Freibeträgen zusammenkommt. • Lösungsplan: • Verwalte die Beschäftigten • z.B. in einer verketteten Liste • Iteriere über die Liste und ermittle die benötigten Daten.
Nutzinfo weiter Zur Konstruktion der Liste • Listenelement: • Attribute: • weiter: Zeiger auf Listenelement Nutzinfo (hier: (Zeiger auf) Beschaeftigter) • Methoden: Holen, Setzen der Nutzinfos Beschäftigter
Zur Konstruktion der Liste • class BeschaeftigtenListenEl { • private: • Beschaeftigter * Nutzinfo; • public: • BeschaeftigtenListenEl * weiter; • Beschaeftigter * Get_Beschaeftigten(); • void Set_Beschaeftigten(Beschaeftigter *);}; • Beschaeftigter * • BeschaeftigtenListenEl::Get_Beschaeftigten(){ • return Nutzinfo;}; • void BeschaeftigtenListenEl:: • Set_Beschaeftigten(Beschaeftigter * wen){ • Nutzinfo=wen;};
Zur Konstruktion der Liste • Zur Liste selbst: • Attribute: • Kopf, Aktuelles Element • Methoden: • Konstruktor • Einfügen in Liste (d.h. Engagieren eines Beschaeftigten), Starten der Iteration Inspektion des aktuellen Elements Weiterschalten (möglich?)/Am Ende der L.
Zur Konstruktion der Liste • class BeschaeftigtenListe { • public: • BeschaeftigtenListenEl * Kopf; • BeschaeftigtenListenEl * • AktuellesElement; • BeschaeftigtenListe(); • void Engagieren(Beschaeftigter *); • void StartIteration(); • Beschaeftigter * • DieserBeschaeftigte(); • int WeiterSchalten(); • };
Zu den Methoden • Konstruktor: • BeschaeftigtenListe::BeschaeftigtenListe() { • Kopf = NULL; • AktuellesElement = NULL;} • Einfügen: • void BeschaeftigtenListe:: Engagieren(Beschaeftigter * wen) { • BeschaeftigtenListenEl * • HilfsKopf = new BeschaeftigtenListenEl; • HilfsKopf->Set_Beschaeftigten(wen); • HilfsKopf->weiter = Kopf; Kopf = HilfsKopf;}
Zu den Methoden • Startiteration: • void BeschaeftigtenListe::StartIteration() { AktuellesElement = Kopf;} • Inspektion des aktuellen Elements : • Beschaeftigter * BeschaeftigtenListe:: • DieserBeschaeftigte() { • if (AktuellesElement == NULL) • return NULL; • else return • AktuellesElement->Get_Beschaeftigten();}
Zu den Methoden • Weiterschalten (+ Am Ende der Liste ?) Es muß klar sein, wann die Liste zu Ende durchlaufen ist. Gib dann -1 aus, und sonst 0; also: • int BeschaeftigtenListe::WeiterSchalten() { • if (AktuellesElement->weiter == NULL) • return -1; • else { • AktuellesElement = • AktuellesElement->weiter; • return 0;}
Zur Entstehung der Liste • Durch Zufallszahlen: • Erzeuge eine ganzzahlige Zufallszahl • über Funktion rand() aus „stdlib.h“ • Abhängig vom Rest der Division durch 4 wird ein entsprechender Beschäftigter erzeugt. • Analog: Erzeuge zufällig Namen. • Baue damit Liste mit (hier:) 15 Einträgen auf.
Code 1 • BeschaeftigtenListe * • Mitarbeiterliste = new BeschaeftigtenListe; • // Erzeugen der Listeneinträge • int zufall=rand(); • char * nme = new char [6]; • nme[5] = '\0'; • cout << "Beschäftigte und • deren Gehälter: "<< endl;
Code 2 • for (int j = 0; j < 15; j++) • { for ( int i = 0;i < 5; i++) • { • nme[i] = (rand()%26)+65; • // Zufallszahlen zwischen 65-91 bestimmen; • entsprechen A-Z • } • int A1_Stunden = zufall%168; • int A2_Stunden = zufall%200; • Beschaeftigter * einBeschaeftigter; • int switsch = zufall % 4;
Code 3 • switch (switsch){ • case 0: einBeschaeftigter • = new AngestellterB1(nme);break; • case 1: • einBeschaeftigter • = new AngestellterB2(nme);break; • case 2: • einBeschaeftigter • = new ArbeiterA1(nme, A1_Stunden);break; • case 3: • einBeschaeftigter • = new ArbeiterA2(nme, A2_Stunden);break;}
Code 4 • Mitarbeiterliste • ->Engagieren(einBeschaeftigter); • einBeschaeftigter->Druck(); • zufall = rand(); • } • cout << endl;
Verwendung der Liste • Akkumulierte Werte berechnen • Akkumulierte Werte ausgeben
Code 1 • // Akkumulierte Werte berechnen: • Mitarbeiterliste->StartIteration(); • Beschaeftigter * akt_Beschaeftigter = Mitarbeiterliste->DieserBeschaeftigte(); • long int gehaltsSumme = • akt_Beschaeftigter->Gehalt(); • long int steuerSumme = • akt_Beschaeftigter->Steuer(); • long int freiBetragsSumme = akt_Beschaeftigter->Freibetrag();
Code 2 • // Akkumulierte Werte berechnen 2: • while (Mitarbeiterliste->WeiterSchalten() == 0) { • akt_Beschaeftigter = • Mitarbeiterliste->DieserBeschaeftigte(); • gehaltsSumme += • akt_Beschaeftigter->Gehalt(); • steuerSumme += • akt_Beschaeftigter->Steuer(); • freiBetragsSumme += • akt_Beschaeftigter->Freibetrag(); • }
Code 3 • // Akkumulierte Werte ausgeben: • cout <<"Insgesamt also (alle Beträge in DM): " • << endl • << "Gehälter:\t\t" << gehaltsSumme • << endl • << "Steuern:\t\t" << steuerSumme • << endl • << "Freibeträge:\t" << freiBetragsSumme • << endl; Steuern 1 Prog Steuern 1 Quelltext
Ausgabe auf Console • Beschäftigte und deren Gehälter: • Arbeiter A1 Name: MZRHL Gehalt: 760 • Arbeiter A1 Name: JOETB Gehalt: 3240 • Angestellter B1 Name: WLTZT Gehalt: 4000 • Angestellter B2 Name: IEMHP Gehalt: 6000 • Arbeiter A2 Name: YBPSW Gehalt: 5010 • Angestellter B1 Name: JCCVJ Gehalt: 4000 • Arbeiter A1 Name: FJEEE Gehalt: 3080 • Angestellter B2 Name: JZYLN Gehalt: 6000 • Arbeiter A1 Name: EXKSZ Gehalt: 520 • Arbeiter A1 Name: ASXFV Gehalt: 1320
Ausgabe auf Console 2 • Beschäftigte und deren Gehälter (Fortsetzung): • Arbeiter A2 Name: FFUCR Gehalt: 2370 • Angestellter B1 Name: JDUGC Gehalt: 4000 • Arbeiter A1 Name: KKKIX Gehalt: 2920 • Angestellter B2 Name: ETOBW Gehalt: 6000 • Angestellter B1 Name: VDFQJ Gehalt: 4000 • Insgesamt also (alle Beträge in DM): • Gehälter: 53220 • Steuern: 19349 • Freibeträge: 10300
Zu beachten • Formulierung nimmt keinen Bezug auf den Typ des Beschäftigten. • Flexibilität durch objektorientierten Zugang • Vererbung • dynamisches Binden • Änderungsfreundlichkeit durch Objektorien-tierung.
AngestellterB3 • • Ist Angestellter • Festgehalt: 8000 DM, Zusatzfreibetrag: 1000 DM • • Berücksichtigung in der Hierarchie: • Einfügen der entsprechenden Klasse. • • Darstellung der Klasse • mit minimalem Aufwand durch Vererbung.