Th. Letschert OOP 2 6. Klassenentwurf II © Th Letschert FH Gießen-Friedberg Th. Letschert OOP 2 Klassenentwurf II - Substitutionsprinzip Seite 2 Th. Letschert OOP 2 Liskovs Substitutionsprinzip A: syntaktische / statisch-semantische Substituierbarkeit Seite 3 Substitutionsprinzip Substitutionsprinzip (Liskov'sches Substitutionsprinzip) Barbara Liskov Werte des Subtyps dürfen überall dort verwendet werden, wo Werte des Typs erlaubt sind. T' < T => T'-Werte vertreten T-Werte Kompatiblität von Typ und Subtyp Zuweisung an Typ-Variablen Parameterübergabe Ergebnisrückgabe Funktionen von Subtyp-Werten von Subtyp-Argumenten von Subtyp-Werten an Typ-Parameter aus Typ- Subtyprelation in Java Widening bei Klassentypen: Subklasse ~> Klasse Widening bei primitiven Typen: primitiver Typ ~> weiterer primitiver Typ Seite 4 Subtypen / Wozu Subtypen machen Code flexibel Code der mit dem Basistyp arbeitet, kommt mit allen Subtypen klar, auch mit denen, die noch gar nicht existieren! Katze Stockente Tier Schleimiger Alien Sie landen erst 20017 auf der Erde. Unser Code wird auch sie bearbeiten! for ( Tier t : tierStapel ) { t.streicheln(); fuettern(t); } Seite 5 Subtypen und Vererbung Substitutionsprinzip und Vererbung Erweiterung einer Klasse zur Subklasse Die Fähigkeiten / Attribute entsprechend des Typs den Subtyp übernommen Weitere Fähigkeiten / Attribute kommen hinzu Substitutionsprinzip ist erfüllt S Sub ubsti typ tuti Typ -Werte onspr in -We d rte ürfen zip: ver tete imme r n. werden in Polymorphe Redefinitionen in der Subklasse Fähigkeit des Typs wird im Subtyp modifiziert Regeln der Redefinition müssen die Gültigkeit des Substitutionsprinzip erzwingen Su Erwe bs ite gilt titutio rung triv nsp : iale rin rwe zip ise Su Rede gilt bstitu finiti nic tion on: ht a sp uto rinzi ma p tisc h Ebenen der Gültigkeit des Substitutionsprinzips Syntaktisch / statisch semantisch: Keine Typfehler durch polymorphe Redefinition Semantisch Keine (inhaltlichen) Programmfehler durch Substitution Seite 6 Substitutionsprinzip und polymorphe Redefinition Unter welchen Bedingungen gilt das Substitutionsprinzip bei polymorphen Redefinitionen? Ist Java streng genug: Sind die Regeln von Java scharf genug, um seine Gültigkeit zu garantieren ? Ist Java zu streng: Gibt es (im Prinzip) gültige Redefinitionen, die von Java ausgeschlossen werden? Seite 7 Substitutionsprinzip und polymorphe Redefinition Java Redefinitionsregel 1: Die Parameter der neuen Methode müssen in Typ und Zahl mit denen der ersetzten Methode übereinstimmen. Regel hinreichend ? (oder nicht streng genug) Regel notwendig ? (oder zu streng) Seite 8 Substitutionsprinzip und polymorphe Redefinition Java Redefinitionsregel 1: Die Parameter der neuen Methode müssen in Typ und Zahl mit denen der ersetzten Methode übereinstimmen. Regel hinreichend ! aber zu streng: Redefinitionsregel 1: Kontravariante Modifikationen im Parametertyp sind kompatibel mit dem Substitutionsprinzip. Seite 9 Substitutionsprinzip und polymorphe Redefinition Redefinitionsregel 1 (Kontravarianz in den Parametern): Kontravariante Modifikationen im Parametertyp sind kompatibel mit dem Substitutionsprinzip. Beim Fressen kann ein Wildhund einen Hund vertreten! Hund Fleisch name: String frisst(Chappi) Java: Entwurf OK, wird aber von Java so nicht umgesetzt. UML: UML ist nicht so exakt definiert, dass das Diagramm eindeutig interpretiert werden kann. (Nimm es als gemaltes Java!) WildHund name: String frisst(Fleisch) Chappi Substitutionsprinzip: Wildhund kommt mit Chappi als Parameter seiner frisst-Methode klar Chappi Kontext bietet Chappi Hunde aller Art leben gut in diesem Kontext Seite 10 Substitutionsprinzip und polymorphe Redefinition Java Redefinitionsregel 2: Der Ergebnistyp der neuen Methode muss gleich dem Ergebnistyp der ersetzten Methode sein oder diesen kovariant verändern Regel hinreichend ? (oder nicht streng genug) Regel notwendig ? (oder zu streng) Seite 11 Substitutionsprinzip und polymorphe Redefinition Java Redefinitionsregel 2: Der Ergebnistyp der neuen Methode muss gleich dem Ergebnistyp der ersetzten Methode sein oder diesen kovariant verändern Regel notwendig und hinreichend Redefinitionsregel 2: Kovariante Modifikationen im Ergebnistyp sind kompatibel mit dem Substitutionsprinzip. Seite 12 Substitutionsprinzip und polymorphe Redefinition Redefinitionsregel 2 (Kovarianz im Ergebnis): Kontravariante Modifikationen im Parametertyp sind kompatibel mit dem Substitutionsprinzip. Bauer Bei der Produktion kann ein Bergbauer einen Bauer vertreten! Futter produziert(): Futter Java: Entwurf OK, und wird so umgesetzt. UML: OK Gras BergBauer produziert (): Gras Futter OK Kontext erwartet Futter Bauer Gras BergBauer Seite 13 OK Substitutionsprinzip / Syntaktisch Regel über die Signatur der substituierten (redefinierten) Methoden: 1. Kontravarianz in den Parametertypen 2. Kovarianz im Ergebnistyp Signatur einer Methode: Name + Zahl/Typen der Parameter + Typ des Ergebnisses Syntaktische / statisch-semantische Regel Seite 14 Substitutionsprinzip und polymorphe Redefinition Beispiel Katze frisst(Maus) KleinTier Genaue Bedeutung: was genau sagt das Diagramm aus WildKatze Maus Konzeptionell OK: handelt es sich um einen korrekten OO-Entwurf, wird also insbesondere das Substitutionsprinzip respektiert ? frisst(KleinTier) In Java (Falls OK): Wie wird der Entwurf, falls OK, in Java umgesetzt, ist insbesondere eine direkte Umsetzung in das Java.Typsystem möglich, oder muss auf Laufzeit-Prüfungen ausgeichen werden ? Seite 15 Substitutionsprinzip und polymorphe Redefinition Beispiel Katze fängt():Maus KleinTier Genaue Bedeutung ? Konzeptuell OK ? In Java (Falls OK)? WildKatze Maus fängt():KleinTier Seite 16 Substitutionsprinzip und polymorphe Redefinition Beispiel Arzt behandelt(Patient) HNOArzt AugenArzt behandelt(HalsPatient) behandelt(AugenPatient) Patient HalsPatient AugenPatient Seite 17 Assoziationen ? Genaue Bedeutung ? Konzeptuell OK ? In Java (Falls OK)? Th. Letschert OOP 2 Liskovs Substitutionsprinzip B: Semantische Substituierbarkeit Seite 18 Substitutionsprinzip / Semantisch Regel über die Spezifikation der substituierten (redefinierten) Methoden: 1. Keine Verschärfung der Vorbedingung 2. Keine Abschwächung der Nachbedingung Semantische Regel Kovarianz und Kontravarianz auf semantischer Ebene Spezifikation einer Methode Vorbedingung Beschreibung der Voraussetzung der Methode: Bedingung unter denen eine Methode ihr korrektes Verhalten garantiert. Nachbedingung Beschreibung der Wirkung der Methode: Bedingung, die nach ihrer Ausführung gilt. Seite 19 Substitutionsprinzip / Semantisch: Beispiel Beispiel / Vorbedingung Ein Stack ist ein Speicher mit LIFO-Verhalten Stack Ein BoundedStack ist ein Stack mit begrenztem Fassungsvermögen push(int) pop():int BoundedStack push(int) pop():int Seite 20 Substitutionsprinzip / Semantisch: Beispiel Beispiel / Vorbedingung Ein Stack ist ein Speicher mit LIFO-Verhalten Stack Ein BoundedStack ist ein Stack mit begrenztem Fassungsvermögen push(int x) pop():int pre: post: x liegt auf dem Stapel BoundedStack push(int x) pop():int pre: darf nicht voll sein post: x liegt auf dem Stapel Seite 21 Substitutionsprinzip / Semantisch: Beispiel Beispiel / Vorbedingung Ein Stack ist ein Speicher mit LIFO-Verhalten Stack Ein BoundedStack ist ein Stack mit begrenztem Fassungsvermögen push(int x) pop():int pre: post: x liegt auf dem Stapel Entwurfsfehler: Verstoß gegen das Substitutionsprinzip ein BoundedStack kann nicht als Vertreter eines Stacks agieren! BoundedStack push(int x) pop():int pre: darf nicht voll sein post: x liegt auf dem Stapel Seite 22 Substitutionsprinzip / Semantisch: Beispiel Beispiel / Nachbedingung Sparvertrag auszahlen():Geld pre: monatlich eingezahlt post: returns kontoStand + 2.5 % Zinsen DagobertSparen auszahlen():Geld pre: wöchentlich eingezahlt post: returns kontoStand + 0.5 % Zinsen Ein Sparvertrag wird bei monaticher Einzahlung mit 2,5% ausgezahlt DagobertSparen, ein Sparvertrag bei der Dagobert-Bank, ist ein spezieller Sparvertrag, der nur 0,5% Zinsen bietet. Seite 23 Substitutionsprinzip / Semantisch: Beispiel Beispiel / Nachbedingung Sparvertrag auszahlen():Geld pre: monatlich eingezahlt post: returns kontoStand + 2.5 % Zinsen Niemand wird ein DagobertSparen als Vertreter eines Sparvertrags akzeptieren! DagobertSparen auszahlen():Geld Entwurfsfehler: Verstoß gegen das Substitutionsprinzip pre: wöchentlich eingezahlt post: returns kontoStand + 0.5 % Zinsen Ein Sparvertrag wird bei monaticher Einzahlung mit 2,5% ausgezahlt DagobertSparen, ein Sparvertrag bei der Dagobert-Bank, ist ein spezieller Sparvertrag, der nur 0,5% Zinsen bietet. Seite 24 Substitutionsprinzip / Semantisch: Beispiel Beispiel Sparvertrag auszahlen():Geld pre: monatlich eingezahlt post: returns kontoStand + 2.5 % Zinsen pre: jährlich eingezahlt post: returns kontoStand + 5 % Zinsen SparvertragS auszahlen():Geld OK ? Seite 25 Substitutionsprinzip / Semantisch Semantische Regel Übertragung des Substitutionsprinzips auf Spezifikationen Vorbedingung Die Vorbedingung einer redefinierten Methode muss gleich oder oder schwächer sein. Nachbedingung Die Nachbedingung einer redefinierten Methode muss gleich oder stärker sein. Sparvertrag auszahlen():Geld SparvertragS auszahlen():Geld pre: monatlich eingezahlt post: returns kontoStand + 2.5 % Zinsen pre: jährlich eingezahlt post: returns kontoStand + 5 % Zinsen OK: Ableitung schwächt Forderung ab und erhöht Leistung. Seite 26 Der Ersatz darf von seinem Verwender nicht mehr verlangen! Der Ersatz darf für seinen Verwender nicht weniger leisten! Su Subs Vo btype titut rbe i din n hab onsp Na gung en sc rinzip chb en h edi und wäch : ngu sc ere nge här fere n Substitutionsprinzip / Beispiel Beispiel Ein Rechteck hat eine Breite und eine Höhe, man kann es zeichnen, man kann Breite und Höhe ändern Ein Quadrat ist eine besondere Art von Rechteck: Breite und Höhe sind immer gleich Menge aller Quadrate Menge aller Rechtecke mengentheortische Sicht der Vererbung / SubtypEigenschaft Rechteck breite: int hoehe: int setBreite(int):void setHoehe(int):void zeichne():void inv: breite = hoehe Quadrat Invariante: Bedingung an den Zustand der Objekte der Klasse. Seite 27 OK ? Substitutionsprinzip / Beispiel Beispiel Ein Rechteck hat eine Breite und eine Höhe, man kann es zeichnen, man kann Breite und Höhe ändern Ein Quadrat ist eine besondere Art von Rechteck: Breite und Höhe sind immer gleich Menge aller Quadrate stimmt nicht diese Quadrate sind keine Rechtecke Menge aller Rechtecke mengentheortische Sicht der Vererbung / Subtyp-Eigenschaft Rechteck breite: int hoehe: int setBreite(int):void setHoehe(int):void zeichne():void inv: breite = hoehe Quadrat Seite 28 Verstoß gegen das Substitutuionsprinzip: Invariante kann verletzt werden. setHoehe / setBreite bei Quadrat ? Die Quadrate können nicht überall an die Stelle von Rechtecken treten. Substitutionsprinzip / Beispiel Beispiel Ein Rechteck hat eine Breite und eine Höhe, man kann es zeichnen, Ein Quadrat ist eine besondere Art von Rechteck: Breite und Höhe sind immer gleich Menge aller Quadrate Menge aller Rechtecke mengentheortische Sicht der Vererbung / SubtypEigenschaft Rechteck breite: int hoehe: int zeichne():void inv: breite = hoehe Quadrat OK ? Seite 29 Substitutionsprinzip / Beispiel Beispiel Ein Rechteck hat eine Breite und eine Höhe, man kann es zeichnen, Ein Quadrat ist eine besondere Art von Rechteck: Breite und Höhe sind immer gleich OK: Objekte werden als Werte (unveränderlich) betrachtet ~ mathematische Sicht auf Quadrate und Rechtecke Menge aller Quadrate Menge aller Rechtecke mengentheortische Sicht der Vererbung / SubtypEigenschaft Rechteck breite: int hoehe: int zeichne():void inv: breite = hoehe Quadrat Substitutionsprinzip nicht verletzt: Invariante der Ableitung kann kann bei Gebrauch als Basis-Objekt nicht verletzt werden. OK ! Wertartige Objekte und Objekte mit Zustand sind im Entwurf zu unterscheiden! Seite 30 Substitutionsprinzip / Beispiel Beispiel Rechteck breite: int hoehe: int setSize(x:int,y: int):void zeichne():void Quadrat pre: x>=0, y>=0 OK ? pre: x>=0, y>=0, x=y setSize(x:int,y: int):void Ein Quadrat ist eine Art von Rechteck: Eins bei dem man die Grösse in x- und in yRichtung immer gleich setzt. Seite 31 Substitutionsprinzip / Beispiel Beispiel Verstoß gegen das Substitutionsprinzip: Verschärfung der Vorbedingung nicht erlaubt! Rechteck breite: int hoehe: int setSize(x:int,y: int):void zeichne():void Quadrat pre: x>=0, y>=0 pre: x>=0, y>=0, x=y setSize(x:int,y: int):void Ein Quadrat ist eine Art von Rechteck: Eins bei dem man die Grösse in x- und in yRichtung immer gleich setzt. Seite 32 Substitutionsprinzip / Beispiel Beispiel Rechteck breite: int hoehe: int setSize(x:int,y: int):void zeichne():void Quadrat pre: x>=0, y>=0 OK ? pre: x>=0, y>=0 throws BadSize if not x=y setSize(x:int,y: int):void Na gut, dann Exception statt Vorbedingung. Seite 33 Substitutionsprinzip / Beispiel Beispiel Rechteck breite: int hoehe: int setSize(x:int,y: int):void zeichne():void Quadrat pre: x>=0, y>=0 Exceptions dürfen nicht hinzugefügt werden! pre: x>=0, y>=0 throws BadSize if not x=y setSize(x:int,y: int):void Seite 34 Substitutionsprinzip / Beispiel Beispiel Rechteck breite: int hoehe: int setSize(x:int,y: int):void zeichne():void Rechteck breite: int hoehe: int setSize(x:int,y: int):void throw BadSize zeichne():void Quadrat Quadrat setSize(x:int,y: int):void throw BadSize setSize(x:int,y: int):void throw BadSize nicht OK OK Seite 35 Substitutionsprinzip / Semantisch Regel über die Spezifikation der substituierten (redefinierten) Methoden: 1. Keine Verschärfung der Vorbedingung 2. Keine Abschwächung der Nachbedingung 3. Keine Verletzung der Invariante 4. Keine zusätzlichen Exceptions Spezifikation einer Methode Vorbedingung Beschreibung der Voraussetzung der Methode: Bedingung unter denen eine Methode ihr korrektes Verhalten garantiert. Nachbedingung Beschreibung der Wirkung der Methode: Bedingung, die nach ihrer Ausführung gilt. Invariante Beschreibung der Bedingung die an den Zustand der Objekte gestellt wird: Bedingung, die nach vor/nach jeder Ausführung einer Methode gilt. Seite 36 Substitutionsprinzip und polymorphe Redefinition Beispiel pre: ...................... post: Patient gesund Arzt fach: Fach behandelt(Patient) HNOArzt AugenArzt behandelt(HalsPatient) behandelt(AugenPatient) Patient krankheit: Krankheit inv: ...................... inv: ...................... HalsPatient AugenPatient Seite 37 Vorbedingung ? Invarianten ? Klassen-Assoziationen Genaue Bedeutung ? Konzeptuell OK ? In Java (Falls OK)? Substitutionsprinzip und polymorphe Redefinition Beispiel Arzt fach: Fach behandelt(Patient) Krankenhaus aufnehmen(Patient) * HNOArzt AugenArzt behandelt(HalsPatient) behandelt(AugenPatient) Patient krankheit: Krankheit HalsPatient AugenPatient Seite 38 Ein Krankenhaus nimmt einen Patienten auf und lässt ihn durch einen seiner Ärzte mit der richtigen Fachrichtung behandeln. In Java ?! Substitutionsprinzip und polymorphe Redefinition Beispiel Arzt behandelt(Patient) Krankenhaus aufnehmen(Patient) * HNOArzt AugenArzt behandelt(HalsPatient) behandelt(AugenPatient) Ein Krankenhaus nimmt einen Patienten auf und lässt ihn durch einen seiner Ärzte mit der richtigen Fachrichtung behandeln. Unterschied zum Beispiel vorher? Patient heilen() Vorbedingungen / Invarianten ? In Java ?! HalsPatient heilen() AugenPatient heilen() Seite 39 Substitutionsprinzip und polymorphe Redefinition Beispiel Arzt behandelt(Patient) throws InkompetentEx Krankenhaus aufnehmen(Patient) * HNOArzt AugenArzt behandelt(HalsPatient) throws InkompetentEx behandelt(AugenPatient) throws InkompetentEx Ein Krankenhaus nimmt einen Patienten auf und lässt ihn durch einen seiner Ärzte mit der richtigen Fachrichtung behandeln. Unterschied zum Beispiel vorher? Patient heilen() Vorbedingungen / Invarianten ? In Java ?! HalsPatient heilen() AugenPatient heilen() Seite 40 Substitutionsprinzip und polymorphe Redefinition Beispiel Arzt behandelt(Patient) throws InkompetentEx Krankenhaus aufnehmen(Patient) * Bitte erweitern um: HNOArzt AugenArzt behandelt(HalsPatient) throws InkompetentEx behandelt(AugenPatient) throws InkompetentEx Patient heilen() HalsPatient heilen() AugenPatient heilen() Seite 41 Ein Krankenhaus nimmt Patienten auf - und lässt sie durch durch seinen Aufnahmearzt untersuchen, - der heilt sie selbst wenn es sich um SchnupfenPatient handelt, sonst verweist er sie an einen der Fachärzte, der dann die Behandlung übernimmt. - Der Aufnahmearzt ist ein Arzt der Fachrichtung AllgemeinMedizin. UML-Modell ? Klassen / abstr. Klassen / Schnittstellen Assoziationen ? Vor-/Nachbedingungen ? Invarianten ? In Java ? Liskov'sches Substitutionsprinzip / Zusammenfassung Substitutionsprinzip: Syntaktisch / statisch semantisch 1. Kontravarianz in den Parametertypen 2. Kovarianz im Ergebnistyp Semantisch 1. Keine Verschärfung der Vorbedingung 2. Keine Abschwächung der Nachbedingung 3. Keine Verletzung der Invariante 4. Keine zusätzlichen Exceptions Einsatz: Richtlinie zum Klassenentwurf Seite 42