EDAF60
Objektorienterad modellering och design Föreläsning 2
Christian.Soderberg@cs.lth.se
2 september 2021
Distansundervisning
▸ Jag hade hoppats att kunna ge denna föreläsning på plats i E:A, men tyvärr är tekniken inte tillräckligt tillförlitlig.
▸ Jag vill gärna träffa så många av er som möjligt, kanske kan vi ha frågestunder IRL i E:A
▸ Denna kurs är väldigt ”framtung” vad gäller föreläsningarna – grundtanken är att vi skall gå igenom allt material tidigt i kursen, så att ni hinner arbeta med det under två projekt.
▸ Det finns tre slags övningsuppgifter:
▸ seminarieövningsuppgifter, som behandlas på seminarierna (duh!) – dessa bör ni försöka lösa på egen hand, eller tillsammans med någon kursare, före seminarierna
▸ uppgifter insprängda i förberedelsetexterna, dessa är mest till för att få er att fundera igenom de begrepp som kommer att behandlas under föreläsningarna
▸ uppgifter insprängda i anteckningarna efter föreläsningarna
Administration
▸ Ni skall göra två projekt, i grupper om 4 studenter – ni får själva bilda grupper som ni vill, men i princip måste varje grupp ha 4 studenter.
▸ Maila mig senast ikväll (torsdag i läsvecka 1) om du eller din grupp vill ha hjälp att hitta någon att göra projekten med.
▸ Er grupp skall för varje projekt delta i ett designmöte – tidigare år har vi haft dem tillsammans med handledaren och en annan grupp, i år kommer vi istället att ha
’designseminarie’‐genomgångar, IRL, där varje grupp får skicka en representant.
Det kommer troligen att bli drygt 40 grupper, och jag hoppas kunna klara av allt med två alternativa tider (högst 60 minuter) per projekt, där alltså gruppen måste hitta en deltagare som kan delta vid varje möte, och sedan rapportera tillbaka.
▸ Nästa vecka lägger jag på kurshemsidan ut en länk till en sida där man kan anmäla sin grupp, och samtidigt välja tid för sina ’designseminariemöten’.
▸ I TimeEdit‐schemat finns ganska många redovisningstider för projekten, nästan alla dessa kommer att utgå, och ersätts alltså med två eller tre alternativa tider i läsveckorna tre och fem (det blir inga redovisningsmöten i läsvecka 7).
Förra gången
▸ Bakgrund
▸ Cohesion och Coupling
▸ Top‐down (önsketänkande)
▸ Inkapsling och lokalitet
Frågor från förra gången
▸ var‐deklarationer
▸ default‐metoder iinterface‐deklarationer
▸ Att skriva klasser medstatic‐metoder för hjälpmetoderna förra gången
▸ Java‐version i kursen?
▸ Jag kommer att använda Java 16
▸ Ni kan använda vilken Java 9+‐version ni vill, men jag rekommenderar er att använda en så modern version som möjligt
Repetition av typer och deklarationer
▸ ”Stark typning”: testar att beräkningar utförs på värden av rätt typ
▸ ”Statisk typning”: testar vid kompileringen att beräkningar kommer att utföras på värden av rätt typ
▸ Med statisk typning kan vi fånga typfel tidigare – för mindre program som vi kör själva spelar det ofta ingen större roll, men för större program som andra skall köra kan det vara en stor hjälp
▸ Java har stark och statisk typning, språk som Python, Clojure, JavaScript och Ruby är dynamiskt typade (de är alla starkt typade)
Repetition av typer och deklarationer
▸ Fråga: Varför deklarerar vi värden i Java?
▸ Svar: För att tala om för kompilatorn vad vi vill kunna göra med dem, dvs så att den statiska typningen skall få den information den behöver för att hjälpa oss
▸ Vi kan använda värden av vilken typ som helst som implementerar den typ vi deklarerar med – detta kallas subtypspolymorfism
Om deklarationer
▸ Undvik deklarationer som:
ArrayList<Integer> findPrimes(ArrayList<Integer> values)...
– de får det att se ut som att man inte vet varför man deklarerar värden
▸ Skriv istället:
List<Integer> findPrimes(List<Integer> values)...
eller, kanske till och med:
List<Integer> findPrimes(Iterable<Integer> values)...
– dvs deklarera så generellt som möjligt, i detta fall gör det att vi kan hantera vilket slags listor som helst, och att vi får lägre ’coupling’ på vägen tillbaka
▸ Deklarera gärna med hjälp av interfaces (vi kommer tillbaka till detta senare i kursen)
Klasser och interfaces
▸ När vi deklarerar en klass i Java så gör vi egentligen två saker samtidigt:
▸ Vi talar om vad man kan göra med objekten (api‐et)
▸ Vi talar om hur det görs (implementationen)
▸ I en del språk gör man detta i separata filer
▸ Även i Java kan vi dela upp, genom att:
▸ Deklarera ett interface
▸ Skriva en eller flera klasser som implementerar interfacet
▸ Ordna sätt att skapa objekten (ofta med ’factories’ eller ’builders’)
▸ Vi återkommer till detta senare
Idag
▸ Modellering och UML‐diagram
▸ Introduktion till SOLID‐principerna
▸ Aritmetiska uttryck
▸ Mönster:
▸ Template Method
▸ Command Pattern
UML
▸ Unified Modeling Language
▸ Standard för att visualisera olika aspekter av ett system
▸ Olika slags diagram:
▸ Funktionell modell: Use cases
▸ Statisk modell: Klassdiagram
▸ Dynamisk modell: Sekvensdiagram, Tillståndsdiagram
▸ Om man skall lära sig något sätt att rita en modell, så är det UML
Klassdiagram – klasser
Point2D - x: Double - y: Double
+ distanceTo(Point): Double
Segment
▸ Tre ’fack’, visar namn, attribut, och metoder
▸ Attribut och metoder kan döljas
▸ Åtkomst till attribut och metoder visas med+,-och#
▸ Ofta visas endast metodsignaturerna (och alltså inte parameternamnen)
Interfaces
≪interface≫ Point
+ distanceTo(Point): Double
▸ Samma regler som för klasser, men«interface»i huvudet
Abstrakta klasser
Point
+ distanceTo(Point): Double
▸ Samma regler som för klasser, men med kursiverat namn
Generalisering
≪interface≫ Point
+ distanceTo(Point): Double
Point2D
▸ Ärvda metoder och attribut skrivs inte ut
▸ Martin ritar heldraget streck även vid implementation av interface, UML använder streckad linje
Generalisering
≪interface≫ Point
+ distanceTo(Point): Double
Point2D Point3D
▸ Man försöker ofta gruppera ihop subklasser och låta dem dela på triangeln, men kan även låta flera öppna trianglar peka mot superklassen
Parametriserade klasser
≪interface≫ List
+ add(E)
+ elementAt(Int): E E
TreeMap
+ add(K,V)
+ get(K): Optional<V>
K,V
Associationer
Company Employee
1 *
Company Employee
Company * Employee
▸ En association visar att det finns något slags relation mellan två klasser
▸ Ibland skriver man namnet på relationen på strecket, ibland även med en pil som visar relationens riktning
▸ Ofta skriver man ut multiplicitet
Aggregation
StudentUnion Student
StudentUnion Student
▸ En aggregation är ett slags association, där något utgör en del av något annat, men där delarna ’har ett eget liv’
Komposition
Keyboard Key
Keyboard Key
▸ En komposition från A till B är ett slags starkare aggregering, där B ägs av A, och där B försvinner när A försvinner
Beroenden
≪interface≫
Observer Observable
▸ Vi använder beroendepilar från klassAtill klassBomAinte har något attribut av klassenB, men får ettB‐objekt som inparameter eller returvärde i någon metod
Exempel
Gör en enkel UML‐modell (klassdiagram) av ett universitet med studenter som läser kurser
Principer
▸ Vi har sett att vi vill ha ’high Cohesion’, och ’loose coupling’
▸ För att få ’high cohesion’ skall ett paket eller en klass eller en metod syssla med saker som hör ihop:
▸ de skall helst bara göra en sak
▸ de skall helst göra hela den saken
▸ För att få ’loose coupling’ vill vi inte vara beroende av en specifik klass, det är bättre om vi kan bero av ett interface, så att vi senare kan välja vem som skall göra det
▸ vi kan skräddarsy ett litet interface
▸ vi kan lägga till nya klasser som implementerar interfacet, utan att ändra vår kod
SOLID‐principerna (Martin)
▸ Single Responsibility Princicple (SRP) (ger ’high cohesion’)
▸ Open Closed Principle (OCP)
▸ Liskov Substitution Principle (LSP)
▸ Interface Segregation (ISP)
▸ Dependency Inversion (DIP) (ger ’loose coupling’)
Exempel
Skriv ett program som beräknar aritmetiska uttryck
Förbättring
▸ Finns det något som ’stör’ i programmet som beräknar uttryck?
▸ Exakt hur ser kod‐dupliceringen ut vidvalue()iAddochMul?
▸ Hur kan vi bryta ut den gemensamma koden?
Template Pattern – före
≪interface≫ Expr + value(): Double
Add
- left, right: Expr + value(): Double
Mul
- left, right: Expr + value(): Double
▸ Här finns det likartad kod iAddochMul
▸ Vi kan bryta ut den gemensamma koden till en superklass
Template Pattern – efter
≪interface≫ Expr + value(): Double
BinOp - left, right: Expr + value(): Double
# op(double, double): Double
Add
# op(double, double): Double
Mul
# op(double, double): Double
Terminologi
▸ Vi vill undvika duplicerad kod: Don’t Repeat Yourself (DRY)
▸ Template Pattern är en tillämpning av DRY
Exempel
Använd Command Pattern för att skriva ett ritprogram med hjälp av interfacet nedan – hur skulle du implementera ”ångra”?
interfaceDrawing { voidsetDrawMode();
voidsetEraseMode();
voidcircle(intx,inty,intradius);
voidsquare(intx,inty,intside);
}
Command Pattern
▸ Inför ett kommando‐interface, detta skall ha en metod för att utföra något (och kan även ha en metod för att ’ta tillbaka’)
▸ Skriv en klass för varje sak som programmet skall kunna göra, låt dessa klasser implementera kommando‐interfacet genom att packa ihop all den information de behöver
▸ Vi kan på detta sätt spara våra kommandon i listor och stackar, och kan enkelt hantera vår kommandohistorik
▸ Programmet blir också mer modulärt, det är enkelt att lägga till nya rit‐kommandon (vi har DIP och SRP, och får på köpet även OCP)