DVD

advertisement
H9: Klasse Ontwerp
Richtlijnen
Specificaties
Multiple inheritence
SchetsPlus...
doe ik het goed ?
2
Hoe maak ik goede klassen ?
 We gaan kijken naar:
 algemene ontwerp-richtlijnen
 software metric
 Complement: style-gidsen, tips, best
practices, kookboeken, enz.
Sun’s Java Coding Style Guide
Ambler, the Elements of Java Style
3
Richtlijnen
 Structuur is belangrijk, wat je niet wil:
 complex  fouten, onderhoudkost
 star
 Optimaliseer :
 encapsulatie
 inheritence
 cohesie
 koppeling
4
Cohesie
 Een “module” is cohesief als het een set van sterk
aan elkaar gerelateerd “functionaliteiten” aanbiedt.
Persoon
getGewicht()
getLengte()
Persoon
getGewicht()
getLengte()
getVrienden()
Persoon
getGewicht()
getLengte()
addInAdresBoek(aboek)
5
Koppeling
 Er is een koppeling tussen modules A en B als een
van de andere afhankelijk is.
Voorbeelden:
 datakoppeling
f() { ... u.g(x) ... }
 globale-var koppeling
• m1,m2 via een static attribuut
•C1, C2 via een package-private attribuut
6
Koppeling
 Pathologisch
Drank
- suiker : int
- water : int
+ zoet() : int
+ roer()
in C++ heb je ook friends.
7
Mixer
if (drank.zoet() > 10) {
drank.water++ ;
drank.roer() ;
}
Koppeling
 In OO ook door:
 Associatie / navigatie
 Verse objecten in methode
 Via inheritence
 Vaak spanningveld tussen koppeling en de andere
aspecten:
 maak A subklasse van B  koppeling
 verhoogt cohesie met delegatie  koppeling
8
Inheritence koppeling
Persoon
getKinderen()
Klant
Drank
mixMetMelk() // concreet
abstract mix()
Thee
Koffie
9
Demeter Principe
 Ian Holland, 1987
“Zorg dat objecten alleen met vrienden praten.”
Vliegtuig
bagageGewicht() :
int
vervoert
*
Persoon
naam
heeft
*
Tas
gewicht
 Delegeer:
Vliegtuig
vervoert *
bagageGewicht() :
int
Persoon
naam
tassenGewicht()
heeft
ten koste van de cohesie van Persoon.
10
*
Tas
gewicht
Connascance
 Page-Jones, 1992.
 Letterlijk: tegelijkertijd geboren.
 Page-Jones: Klassen C en D zijn connascent als het
mogelijk is om C aan te passen die een aanpassing
van D dwingt.
 koppeling!
11
Uit project management perspectief
 Software metriek  complexiteit indicatoren
 Om strategisch te beslissen dat bepaalde delen van
de software een risico factor zijn, en dat
reorganisatie nodig is.
 Voor programmeurs ook nuttig als richtlijnen.
12
Voorbeeld
 Metriek :
+ Uit te rekenen (en goedkoop)  tools!
- abstract
 Zoals, #regels
 Nog meer? Traditionele metrieken
 Halstead
 McCabe
 Oviedo
 OO metriek
 “de” metriek bestaat niet  ze zijn allemaal indicatoren.
13
Halstead
 Complexiteit: moeite om code te lezen
E = D*V
x = x + x ; x++
x = x + y ; z++
(alleen ter info)
14
McCabe
 Het aantal lineair onafhankelijke paden in je
programma.
int P() {
if (...) return 100
else return 0
}
0
1
2
Control Flow Graph (CFG)
15
McCabe
0
4
1
3
2
5
16
Oviedo
 Splits programma in sequentiële blokken
 interacties tussen elementen in een blok voegen niets
aan complexiteit.
 afhankelijkheden tussen blokken wel.
 Voorbeeld:
P(int x, int y) {
if (y>0) x = 0 ; else
x=1;
(y>0) ; x = 0
(~y>0) ; x = 1
DF = 2
DF = 2
return x
}
17
return x
DF(P) = 6
DF = 2
OO metriek
 Voor OO willen we ook indicatie hebben over
structurele complexiteit van je klassen.
 Chen & Lu, 1993:
 Encapsulatie
 Koppeling
 Inheritence
 Cohesie
18
Encapsulatie (P)
 Idee:
 Methode met minder argumenten is abstracter
 Simpel vs complex parameters, bijvoorbeeld:
Type
Complexiteit waarde
boolean, int
0
double
2
object
6-9
 P = som van de complexiteit van de argumenten
(van pub. methodes) in C.
19
Koppeling (Cp)
 Idee
 C gebruikt D  1x koppeling
 C wordt door D gebruikt  1x koppeling
 wederzijde koppeling  lastig  telt als extra
 Cp = som van boven.
20
Cohesie Co
 Hoe weten we welke methode bij elkaar horen??
 Idee: methodes met dezelfde type signatuur horen
vaak bij elkaar.
Chen en Lu  ook “sub” signatuur.
m1(int,Vervoer) ~
m2(Vervoer,int,Persoon)
Vervoer
+ versnel(real)
+ addPassagier(Persoon)
+ swapPassagiers(Persoon, Persoon)
+ addPassagiers (Collection<Persoon>)
21
Co = G / N = 0.75
Inheritence H
 Inheritence is goed (code hergebruik), maar je code
wordt ook minder expliciet  in zekere zin ook fout
gevoelig.
 H is een meting van inheritence complexiteit. Som
van:
 # methodes
 inheritence afstand
 # direct superklassen.
 # subklassen
22
JHawk
23
Klasse specificatie
Minderjarig
bonus
Klant
Naam
Leeftijd
Videotheek
leent
*
DVD
titel
leeftijdgrens
< is verantwoordelijk voor
 Meer kun je niet met klasse diagram uitdrukken...
 Een klant is een mj als zijn/haar leeftijd ≤ 18
 De klant die voor een mj verantwoordelijk is, is zelf
geen mj.
24
.
Klasse invariant
 Een klasse invariant van C is een constraint op de
attributen van de objecten van C.
 Anders zit een object in een verkeerde/onveilig
toestand.
Minderjarig
Bob
10
Minderjarig
Octo
30
De leeftijd van een mj is  18.
 Het gaat over de stabiele toestand van een object
25
(dus niet als een operatie nog bezig is met het
object).
Klasse invariant
 Maar indirect gaat het eigenlijk ook over associaties...
DVD
Sneeuwwit
0+
Minderjarig
Bob
10
DVD
Star Trek
10+
DVD
Kill Bill
12+
 Hoe belangrijk?  erg belangrijk.
26
Hoe druk je dat uit?
 Met “predicaten” zoals in Logica :
(forall x : Minderjarig  x.leeftijd  18)
 “Object Constraint Language” (OCL)  onderdeel
van UML.
context x : Minderjarig
inv: x.leeftijd  18
27
Navigatie in OCL
Klant
Naam
Leeftijd
leent >
lener
*
dvds
DVD
titel
leeftijdgrens
context dvd : DVD
inv: dvd.lener.leeftijd  dvd.leeftijdgrens
context x : Klant
inv: x.leeftijd  x.dvds.leeftijdgrens
levert een verzameling terug!
28
Collecties in OCL
 Zoals Set en Sequence
 Operatoren zoals:
 size(), sum(), isEmpty()
 includes(x)
 forAll(...), exists(...), select(…)
 Eigenaardig syntax:
u  isEmpty()
u  includes(x)
29
Voorbeeld
Klant
Naam
Leeftijd
leent
lener
*
dvds
DVD
titel
leeftijdgrens
context x : Klant
inv: x.leeftijd  x.dvds.leeftijdgrens
inv: x.dvds

forall (dvd | x.leeftijd  dvd.leeftijdgrens)
30
Filter  select operatie
Klant
Naam
Leeftijd
leent
lener
*
dvds
DVD
titel
premium : boolean
Je mag slechts één permium DVD lenen.
context x : Klant
inv: x.dvds

select (dvd | dvd.premium = true)

size() ≤ 1
31
Methode specificeren
Klant
inschrijf()
leen(d)
getLeenLimiet()
Pre/Post spec,
pseudo code, geen
OCL.
declaratief !
Inschrijf() dient de collectie van gelende dvds op leeg
te zetten
forall x : Klant { true } x.inschrijf() { x.dvds =  }
context x : Klant:: inschrijf()
pre: true
post: x.dvdsisEmpty()
32
Mix in specificatie met “query”
Klant
inschrijf()
leen(d)
getLeenLimiet()
Je mag niet meer dan je limiet lenen.
markeer als ‘isQuery’, maar alleen als side-effect vrij!
context x : Klant:: leen(d)
pre:
x.dvds  size() + 1 ≤ x.getLeenLimiet()
post: x.dvds = x.dvds@pre  insert(d)
33
Multiple inheritence
Product
ID
Naam
Prijs
GroteBestelling
koopGroot(n)
ImportGoed
invoerBelasting()
Koffie
 Krachtig !
Je kunt makkelijk verschillende features erven.
 Talen met MI  C++. Eiffel, Python
 Om uit te kijken  diamantprobleem
34
 Als je toch in Java wil implementeren …
Feature clash…
Werknemer
werk()
Welke werk() wordt
bedoelt in Muzikant ?
(soms de ene soms de
andere)
Artiest
werk()
Muzikant
 Geen echte issue. Eiffel  renaming
class Muzikant inherit
Werknemer rename werk as werk1
Artiest
rename werk as werk2
feature
…
end
35
Diamantprobleem
Persoon
Naam
Leeftijd
Werknemer
Artiest
Muzikant
 Een muzikant kan in principe 2x namen en leeftijden
erven.
 leefdtijd  onzinnig  merge tot 1x
 naam  misschien wil je een echte naam en een
artiestnaam.
 Ambigu  compiler kan deze niet zelf beslissen…
36
Inheritence vs associatie
W
Artiest
Naam
Werk()
Artiest
Naam
Werk()
Muzikant
Muzikant
Feature erven
Is M ook een A ?
37
MI
Ja
Delegatie
Ja
Ja
Nee
Simuleren met assoc + interface
Artiest
Naam
Werk()
W
Gedoe ..
Als MI essentieel in je ontwerp
is, implementeer ook in een MI
taal.
Muzikant
Anders haal MI uit je ontwerp.
W
Artiest (Interface)
Werk()
Muzikant
38
Andere overweging:
persistence.
Artiest
Naam
Werk()
Download