Principles of subclasses Objekt-orienterad programmering och design (DIT953) Niklas Broberg, 2018

Relevanta dokument
Principles of subclasses. Objekt-orienterad programmering och design Alex Gerdes, 2018

Föreläsning 5. När skall man använda implementationsarv? När skall man använda implementationsarv?

Generics och polymorfism. Objekt-orienterad programmering och design (DIT952) Niklas Broberg, 2016

Generics och polymorfism. Objekt-orienterad programmering och design (DIT953) Niklas Broberg / Johannes Åman Pohjola, 2018

Static vs Dynamic binding Polymorfism. Objekt-orienterad programmering och design (DIT953) Niklas Broberg, 2018

UML. Objekt-orienterad programmering och design (DIT952) Niklas Broberg, 2016

Föreläsning 5. När skall implementationsarv användas? The Open-Closed Principle (OCP) Liskov Substitution Principle (LSP)

Föreläsning 5. När skall man använda implementationsarv?

Mutability och State. Objekt-orienterad programmering och design (DIT953) Niklas Broberg / Johannes Åman Pohjola, 2018

Classes och Interfaces, Objects och References Objekt-orienterad programmering och design (DIT952) Niklas Broberg, 2016

Objekt-orienterad programmering och design. DIT953 Niklas Broberg, 2018

Static vs Dynamic binding Polymorfism. Objekt-orienterad programmering och design Alex Gerdes, 2016

Classes och Interfaces, Objects och References, Initialization

Sammanfattning och Tentamensinfo Objekt-orienterad programmering och design (DIT953) Niklas Broberg, 2018

JUnit. Ska kompletteras med kodexempel på JUnit. DD2385 Programutvecklingsteknik Några bilder till föreläsning 12 21/5 2012

Objekt-orienterad Programmering och Design. TDA551 Alex Gerdes, HT-2016

Generic type declarations. Objekt-orienterad programmering och design (DIT952) Niklas Broberg, 2016

Subtyping, co- och contra-variance. Objekt-orienterad programmering och design Alex Gerdes, 2016

Separation of Concern. Objekt-orienterad programmering och design (DIT952) Niklas Broberg, 2016 Johannes Åman Pohjola, 2017

Separation of Concern. Objekt-orienterad programmering och design (DIT953) Niklas Broberg / Johannes Åman Pohjola, 2018

Design Patterns. Objekt-orienterad programmering och design Alex Gerdes, 2016

Kursombud. Objektorienterad modellering och diskreta strukturer / design. Agile? Designprinciper EDAF10 EDA061. Lennart Andersson. Grupper för projekt

TDA550 Objektorienterad programvaruutveckling IT, forts. kurs Övning vecka 2

Dependencies High cohesion, low coupling. Objekt-orienterad programmering och design Alex Gerdes, 2018

Objekt-orienterad Programmering och Design. TDA552 Alex Gerdes, HT-2018

Föreläsning 8 - del 2: Objektorienterad programmering - avancerat

Objektorienterad programmering i Java, datastrukturer och algoritmer. Föreläsning 4 Jonas Lindgren, Institutionen för Datavetenskap, LiU

Subtyping, co- och contra-variance. Objekt-orienterad programmering och design (DIT952) Niklas Broberg, 2016 Johannes Åman Pohjola, 2017

F8 - Arv. ID1004 Objektorienterad programmering Fredrik Kilander

Dependencies High cohesion, low coupling. Objekt-orienterad programmering och design (DIT953) Niklas Broberg, 2018

Design Patterns. Objekt-orienterad programmering och design Alex Gerdes, 2018

Återanvändning. Två mekanismer. Nedärvning av egenskaper (inheritance) Objekt komposition

Föreläsning 8. Arv. Arv (forts) Arv och abstrakta klasser

Outline. Objektorienterad Programmering (TDDC77) Signatur. Klassen calculator. Överlagring (overloading) Arv (inheritance) Ahmed Rezine

Java-syntax (arv) Exempel: public class Crow extends Bird {... } Jämför med Lab 1: public class FirstApp extends Frame {... }

Objektorienterad Programmering (TDDC77)

Modulär design Objekt-orienterad programmering och design (DIT952) Niklas Broberg, 2016

Modulär design. Objekt-orienterad programmering och design (DIT953) Niklas Broberg / Johannes Åman Pohjola, 2018

Static vs Dynamic binding Override vs Overload. Objekt-orienterad programmering och design Alex Gerdes och Sólrún Halla Einarsdóttir, 2018

Arv. Fundamental objekt-orienterad teknik. arv i Java modifieraren protected Lägga till och modifiera metoder med hjälp av arv Klass hierarkier

Instuderingsuppgifter läsvecka 2

UML Objektdiagram. Objektorienterad modellering och design (EDAF25) Föreläsning 3. UML Sekvensdiagram. UML Objektdiagram. Agenda

Design Patterns Objekt-orienterad programmering och design (DIT952) Niklas Broberg, 2017

Innehåll. dynamisk bindning. och programmering CRC) u Arv, polymorfi och

Objektorienterad programmering. Grundläggande begrepp

Grundläggande programmering, STS 1, VT Sven Sandberg. Föreläsning 14

TDDC30. Objektorienterad programmering i Java, datastrukturer och algoritmer. Föreläsning 4 Erik Nilsson, Institutionen för Datavetenskap, LiU

Typhierarkier del 1 Gränssnitt, ärvning mellan gränssnitt, ärvning mellan klasser

Föreläsning 3 Arvsmekanismen Variabler och typer Typer och subtyper

TDDC30. Objektorienterad programmering i Java, datastrukturer och algoritmer. Föreläsning 2 Jonas Lindgren, Institutionen för Datavetenskap, LiU

TDDE10 m.fl. Objektorienterad programmering i Java Föreläsning 6 Erik Nilsson, Institutionen för Datavetenskap, LiU

Arv (Inheritance) Multipelt arv finns i verkligheten. Överskuggning, metodbindning. Läsanvisning: ! Arv! Object, instanceof! Relationer!

Viktiga programmeringsbegrepp: Kontrakt

Undantag, Sammanfattning och Tentamensinfo. Objekt-orienterad programmering och design Alex Gerdes, 2016

Arv. Objektorienterad och komponentbaserad programmering

Subtyping och variance. Objekt-orienterad programmering och design Alex Gerdes, 2018

Arv: Fordonsexempel. Arv. Arv: fordonsexempel (forts) Arv: Ett exempel. En klassdefinition class A extends B {... }

TDDD78, TDDE30, 729A Typhierarkier del 2 Vad krävs? Hur fungerar det?

Föreläsning 15: Repetition DVGA02

TDDE10 TDDE11, 725G90. Objektorienterad programmering i Java, Föreläsning 3 Erik Nilsson, Institutionen för Datavetenskap, LiU

Lösningsförslag till tentamen

Arv och klassbibliotek

TDDC76 - Programmering och Datastrukturer

Observer Pattern och MVC. Objekt-orienterad programmering och design (DIT953) Niklas Broberg, 2018

Objektorienterad Programmering (TDDC77)

Outline. Objektorienterad Programmering (TDDC77) Laborationsserie del två. Vad händer under HT2. Introduktion HT2 UML.

Outline. Objektorienterad Programmering (TDDC77) Åsidosättning. Signatur. Åsidosättning. Abstrakta klasser. Ahmed Rezine.

Objektorientering - Arv och polymorfi. Eric Elfving Institutionen för datavetenskap

TDDE10 m.fl. Objektorienterad programmering i Java Föreläsning 6 Erik Nilsson, Institutionen för Datavetenskap, LiU

Objekt, klasser. Tillstånd Signatur Kommunikation Typ. Fält, parametrar och lokala variabler. Konstruktorer Metoder DAVA15

Objektorienterad Programkonstruktion. Föreläsning 2 2 nov 2016

Typecasting - primitiva typer. Innehåll. DoME klasser

Imperativ programmering. Föreläsning 4

Föreläsning 9: Arv och UML

2I1049 Föreläsning 5. Objektorientering. Objektorientering. Klasserna ordnas i en hierarki som motsvarar deras inbördes ordning

Principer, Patterns och Tekniker. Objekt-orienterad programmering och design (DIT953) Niklas Broberg / Johannes Åman Pohjola, 2018

Lösningsförslag. 1 Lösningsförslag. Uppgift 1

Tentamen Programmering fortsättningskurs DIT950

Outline. Objektorienterad Programmering (TDDC77) Att instansiera en klass. Objekt. Instansiering. Åtkomst. Abstrakt datatyp.

Introduktion och OO. Objekt-orienterad Programmering och Design (TDA552) Alex Gerdes, HT-2018

DAT043 - Föreläsning 7

Objektorienterad Programmering (TDDC77)

Idag. statiska metoder och variabler. private/public/protected. final, abstrakta klasser, gränssnitt, delegering. wrapper classes

Objektorienterade programmeringsspråk. Objektorienterade språk. Den objekt-orienterade modellen. Jämför med icke-oo

TDA550 Objektorienterad programmering, fortsättningskurs. Föreläsning 1. Introduktion Variabler och typer

Arv innebär att man skapar en ny klass (subklass) utifrån en redan existerande klass (superklass, basklass).

Ärvning av implementation. Ärvning av implementation, inklusive abstrakta klasser Hur ska vi ärva? När ska vi ärva?

Lösningsförslag till exempeltenta 2

TDDC30. Objektorienterad programmering i Java, datastrukturer och algoritmer. Föreläsning 11 Jonas Lindgren, Institutionen för Datavetenskap, LiU

Idag. Exempel, version 2. Exempel, version 3. Ett lite större exempel

Abstrakt klass. DD2385 Programutvecklingsteknik Några bilder till föreläsning 4 7/ Exempel: Implementation av Schackpjäser.

Lösningar till tentamen i EDAF25

Objektorienterad Programmering (OOP) Murach s: kap 12-16

TDA550 Objektorienterad programvaruutveckling IT, forts. kurs Övning vecka 3

Objektorienterad Programkonstruktion. Föreläsning 4 8 nov 2016

public class BoundedCounter {

Introduktion till arv

Vad handlar kursen om? Algoritmer och datastrukturer. Vad handlar kursen om? Vad handlar kursen om?

Principer, Patterns och Tekniker. Objekt-orienterad programmering och design (DIT952) Niklas Broberg, 2016

Design Patterns. En kort introduktion

Transkript:

Principles of subclasses Objekt-orienterad programmering och design (DIT953) Niklas Broberg, 2018

Implementation inheritance Subclassing, eller implementation inheritance (implementationsarv), ger oss två fördelar: Polymorfism Ett objekt av en subclass kan användas som om det var ett objekt av sin superclass. Ger flexibilitet, Plug-n-play ; kan e.g. arbeta med listor av objekt med superklassen som statisk typ, som vid run time kan vara av antingen superclass eller (någon) subclass. Återanvändning av kod (code reuse) Definiera gemensamma metoder i superklassen som kan ärvas av dess subclass(es). Don t repeat yourself, ingen cut-n-paste. Ger ett enda ställe för förändring vid behov maintainability.

Polymorfism reclaimed Polymorfism kan åstadkommas med hjälp av ett interface istället: Polygon + paint(graphics) : void + overlaps(polygon) : boolean IPolygon <<interface>> + paint(graphics) : void + overlaps(polygon) : boolean Rectangle + overlaps(rectangle) : boolean Polygon + paint(graphics) : void + overlaps(polygon) : boolean Rectangle + paint(graphics) : void + overlaps(polygon) : boolean + overlaps(rectangle) : boolean

Code reuse reclaimed Code reuse kan åstadkommas med hjälp av delegering istället: Polygon + paint(graphics) : void + overlaps(polygon) : boolean IPolygon <<interface>> + paint(graphics) : void + overlaps(polygon) : boolean Rectangle - parent : Polygon + paint(graphics) : void + overlaps(polygon) : boolean + overlaps(rectangle) : boolean class Rectangle { private Polygon parent = public boolean overlaps(polygon other) { parent.overlaps(other); } } Ärvd metod via delegering

Motivation Antag att vi har behov av att utnyttja polymorfism har behov av att återanvända kod Är det då fritt fram att använda implementation inheritance? Ledande fråga: Svaret är nej, det är inte riktigt så enkelt.

En person är en hund Dog - name : String - birthdate : Date + getname() : String + getbirthdate() : Date Vi (antar att vi) har behov av polymorfism (e.g. en lista som innehåller både hundar och personer). Vi har återanvändning av kod. Person - employer : Company Så vad är problemet?? + getemployer() : Company

Konceptuell Is-A Även om lösningen rent tekniskt åstadkommer det vi behöver, så är det inte en konceptuellt bra lösning. En person är inte en hund. Kod baserat på antagandet att en person är en hund kommer vara mycket förvirrande. Vi tappar simplicity, readability, maintainability. Slutsats: Använd aldrig implementation inheritance om det inte föreligger ett faktiskt, konceptuellt delmängds -förhållande mellan sub- och superclass.

Bättre version LivingBeing - name : String - birthdate : Date + getname() : String + getbirthdate() : Date Dog Person - employer : Company + getemployer() : Company

Motivation andra försöket Antag att vi har behov av att utnyttja polymorfism har behov av att återanvända kod har ett konceptuellt Is-a -förhållande Är det fritt fram att använda implementation inheritance nu då? Svar: Nej

Roller i ett rollspel Player User - username : String + getusername() : String GameMaster Vi har behov av polymorfism (e.g. en lista av alla användare oavsett typ). Vi har kod vi vill återanvända. Både spelare och spelledare är konceptuellt användare. + playermethod() : void + gamemastermethod() : void Så vad är problemet??

Stabil Is-A med unika positioner En användare kan i vissa sammanhang vara en spelare, i andra sammanhang en spelledare. Hur representerar vi detta? Om vi använder ett Player-objekt för att representera användaren i rollen som spelare, och ett GameMaster-objekt för att representera användaren i rollen som spelledare, då kommer dessa två objekt att båda ärva all data (e.g. username) från User. Denna data dupliceras över två separata objekt. Ändras datan måste den uppdateras på båda ställena för att inte få inkonsekvens problem!

Delegering för roller Vid delegering kan samma User-objekt återanvändas för båda rollerna, vilket undviker problemet. Slutsats: Använd inte implementation inheritance för att representera roller som objekt kan ha använd alltid delegering i sådana fall. I en korrekt subclass-hierarki återfinns varje objekt på ett enda ställe, och ändras inte. :Player user = :User username = nbroberg :GameMaster user =

Live code User, Player, GameMaster

Motivation tredje försöket Antag att vi har behov av att utnyttja polymorfism har behov av att återanvända kod har ett konceptuellt och stabilt Is-a -förhållande Är det fritt fram att använda implementation inheritance nu då? Svar: Nej

Squaring off Rectangle - width : int - height : int + getwidth() : int + getheight() : int + getarea() : int + setwidth(int) : void + setheight(int) : void + setsize(int,int) : void Square + setsize(int) : void Vi har behov av polymorfism. Vi har kod vi vill återanvända. En kvadrat är konceptuellt sett en rektangel, och kommer alltid att vara det (stabilt förhållande). Så vad är problemet??

Två perspektiv på subklasser Object Object Rectangle Rectangle Square Square Fokus på delmänger: Vad ett objekt är. Fokus på beteende: Vad ett objekt kan.

Delmängder av många anledningar, subklasser endast av en En delmängd kan uttryckas som en property: Om B A, då har vi B = { x x A, P(x) } för något P. Av alla objekt i A är det bara de som uppfyller P som är i B. Sådana properties kan komma i otaliga former endast en form av property lämpar sig för subklassning: när P(x) indikerar att elementen i B kan något som elementen i A inte kan. Elementen i B har utökat beteende jämfört med elementen i A. Notera: vi arbetar med aktiva och (ofta) muterbara objekt.

Dåliga anledningar Några exempel på konceptuella Is-a -relationer som inte lämpar sig för subclassing: P(x) indikerar att x har begränsat beteende, i.e. inte kan något som övriga kan. E.g. en åskådare i ett dataspel är en spelare som inte kan agera. P(x) indikerar en extern begränsning. E.g. en kvadrat är en rektangel som måste ha lika långa sidor. P(x) indikerar ett temporärt tillstånd. E.g. en användare är ibland en spelare, med då temporärt utökat beteende. E.g. en öppen fil är en fil med temporärt utökat beteende, e.g. läsa från och skriva till. Mer om hur vi hanterar tillstånd (state) i block 6-2.

Motivation fjärde försöket Antag att vi har behov av att utnyttja polymorfism har behov av att återanvända kod har ett konceptuellt och stabilt Is-a -förhållande med unika positioner har ett publikt gränssnitt för subklassen som är en utökning av superklassens Är det fritt fram att använda implementation inheritance nu då? Svar: Fortfarande nej

Forcerat gränssnitt Rectangle - width : int - height : int + getwidth() : int + getheight() : int + getarea() : int + setwidth(int) : void + setheight(int) : void + setsize(int,int) : void class Square extends Rectangle { @Override public void setsize(int w, int h) { this.setsize(w); } // Square + setsize(int) : void }

Live code Rectangle, Square

Liskov Substitution Principle If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2, then S is a subtype of T. (Barbara Liskov) S är en äkta subtyp till T endast om, för varje publik metod som finns i både S och T: S s metod godtar alla värden som T s metod godtar S gör alla beräkningar på denna indata som T gör (och kanske fler).

S.O.L.I.D principles Single Responsibility Open-Closed Liskov Substitution Interface Segregation Dependency Inversion Principle

Motivation femte försöket Antag att vi har behov av att utnyttja polymorfism har behov av att återanvända kod har ett konceptuellt och stabilt Is-a -förhållande med unika positioner har ett publikt gränssnitt för subklassen som är en utökning av superklassens har ett publikt beteende för subklassen som är en utökning av superklassens Är det fritt fram att använda implementation inheritance nu då? Svar: Ja, men

Slutsatser För att implementation inheritance alls ska vara lämpligt: Ett konceptuellt Is-a -förhållande måste föreligga. Om inte använd ett gemensamt interface och/eller delegering. Vi måste ha (möjligen framtida) behov av polymorfism. Om inte använd enkel delegering. Vi måste ha behov av att återanvända kod. Om inte använd interfaces. Subklassens publika gränssnitt ska inkludera superklassens. Om inte bryt ut det gemensamma gränssnittet till ett interface som båda implementerar. Subklassen ska lägga till extra beteenden och beräkningar, inte ändra redan befintliga. Om inte hitta minsta gemensamma nämnare i beteende och gör denna antingen till (abstrakt) superklass för båda, eller en (privat) klass som båda delegerar till.

Med det sagt Nu är det fritt fram att använda implementation inheritance! men fortfarande inte nödvändigt, eller ens rekommenderat. Fundera alltid ett varv extra om det är motiverat att använda interfaces och/eller delegering istället är alltid: mer flexibelt du kan bilda explicita relationer mellan objekten som inte begränsas av subclass-superclass. mer precist du kan välja exakt de delar som behövs för code reuse och/eller polymorfism. men mer verbost kan göra koden mer svårläslig. Ställer också mer krav på programmeraren att göra det rätt. Glöm inte att du bara har en möjlighet till att välja superclass (single inheritance), men kan implementera obegränsat antal interfaces.

Printer + print() vs IPrinter <<interface>> + print() LaserPrinter InkPrinter LaserPrinter InkPrinter + changetoner() + print() + changeink() + print() + changetoner() + changeink() PrinterHelper + printhelp()

Live code ChangeCounterRectangle

Starkt beroende Implementation inheritance innebär ett starkt beroende på superklassen. Starka beroenden är dåliga för våra mål: extensibility, reusability, maintainability. Mycket mer om beroenden fr o m block 4-1. Favor composition over inheritance.

Fragile base class problem Fragile Base Class är ett begrepp som syftar till detta problem: Ett starkt beroende från subklassen till superklassens metoder gör att en senare ändring i superklassen kan fördärva subklasser som den inte ens känner till. Rekommendation: Exponera aldrig interna variabler direkt till subklasser (dvs gör dem private), använd getters och setters. Gör alla metoder som inte måste kunna omdefinieras final, så att subklasserna alltid får superklassens beteende. vilket riskerar bryta mot OCP! Min rekommendation: undvik subklassning i möjligaste mån!

What s next Block 3-1: Subtyping, co- och contra-variance