Objektorienterad modellering och design (EDAF25) LongWord

Objektorienterad modellering och design (EDAF25)
LongWord
Föreläsning 7
Agenda
Paketdesign
I vilken klass skall man beräkna summan av de värden som finns i två
LongWord-objekt?
Namngivning
Är det så här man skall göra?
Designmönster (Factory Method)
public class Add implements Instruction {
private LongWord word1, word2;
public void execute() {
long value1 = word1.getValue();
long value2 = word2.getValue();
LongWord word = new LongWord(value1 + value2);
// omissions
}
}
Övning (Observer, Null Object, Composite, UML)
Exempel från projektet Computer
Att göra de närmaste veckorna:
laboration 4 redovisas på onsdag!
jobba med projekt 1
läs Martin kapitel 29
EDAF25 (F7)
VT 2015
1 / 44
LongWord
Det ska göras i den klass där man har tillgång till representationen av
värdena.
VT 2015
2 / 44
VT 2015
4 / 44
Sammanhangsprinciper (package cohesion)
Common reuse principle (CRP)
Reuse-release equivalence principle (REP)
Common closure principle (CCP)
public class LongWord {
private long value;
public void add(LongWord word1, LongWord word2) {
value = word1.value + word2.value;
}
}
Stabilitetsprinciper (package coupling)
Acyclic dependencies principle (ADP)
Stable dependencies principle (SDP)
Stable abstractions principle (SAP)
Varför det?
EDAF25 (F7)
EDAF25 (F7)
Designprinciper för paket
VT 2015
3 / 44
EDAF25 (F7)
Designprinciper för paket
Designprinciper för paket
Common reuse principle (CRP)
Reuse-release equivalence principle (REP)
REP
The granule of reuse is the granule of release
Klasserna i paketet är så nära relaterade att om man behöver en av dem så
behövs i regel även de övriga.
Exempel: Mjukvarupaketet i Computer. Om man behöver en
instruktion så behövs också de andra instruktionerna och
Program-klassen.
Återanvändning (reuse) innebär att det är paketägaren som underhåller och
ger ut (release) paketet. Den som använder paketet skall inte behöva ändra
på paketet och inte behöva titta på implementeringen och bestämmer själv
när en ny utgåva skall integreras.
Exempel: När hårdvarugruppen i det stora Computer-projektet
kommer med en ny version av hårdvaran så kan simuleringsgruppen
själv bestämma när den skall uppgradera hårdvaran och kan göra det
utan att titta på implementeringen.
Motsvarighet: Principen om enkelt ansvar.
Motsvarighet: Lokalitets- och integritetsprinciperna
Handlar om underhåll, spårbarhet och konfigurationshantering.
EDAF25 (F7)
VT 2015
5 / 44
EDAF25 (F7)
Designprinciper för paket
Designprinciper för paket
Common closure principle (CCP)
Stabilitetsprinciper
Klasserna i ett paket skall vara stängda resp. öppna tillsammans gentemot
samma slags förändringar. Förändringar som påverkar en klass i paketet får
påverka andra klasser i paketet men inga klasser utanför paketet.
VT 2015
6 / 44
Acyclic dependencies principle (ADP) – Paket skall ej vara cykliskt
beroende.
Exempel: När vi vill introducera VeryLongWord i Computer-projektet
skall man bara behöva ändra i hårdvarupaketet.
Stable dependencies principle (SDP) – Beroenden skall gå mot stabila
paket.
Motsvarighet: öppen/sluten-principen. Single-responsibility
principen.
Stable abstractions principle (SAP) – Stabila paket skall vara
abstrakta.
EDAF25 (F7)
VT 2015
7 / 44
EDAF25 (F7)
VT 2015
8 / 44
Designprinciper för paket
Designprinciper för paket
Cykelproblem
Cykelproblem
Med cykel
Paketstrukturen kan inte byggas “top down” – inte det första man gör
i sin systemdesign.
Ett paket som ingår i en cykel går inte att återanvända utan att ta
med hela cykeln och allt som cykelns paket beror på.
EDAF25 (F7)
VT 2015
9 / 44
package b;
import a.A;
public class B {
private A a;
public void method() {
a.methodA(this);
}
}
package a;
import b.B;
public class A {
public void methodA(B b) {
b.method();
}
}
EDAF25 (F7)
Designprinciper för paket
Designprinciper för paket
Cykelproblem
Exempel DIP vs SDP
VT 2015
10 / 44
VT 2015
12 / 44
Beroenden mot konkreta klasser:
PolicyLayer
Utan cykel
package a;
public interface AI {
public void method();
}
public class A {
public void methodA(AI ai) {
ai.method();
}
}
package b;
import a.A;
public class B implements AI {
private A a;
public void method() {
a.methodA(this);
}
}
MechanismLayer
UtilityLayer
EDAF25 (F7)
VT 2015
11 / 44
EDAF25 (F7)
Designprinciper för paket
Designprinciper för paket
Exempel DIP vs SDP
Exempel DIP vs SDP
Beroenden mot instabila paket:
Policy
DIP: Beroenden mot abstraktion
PolicyLayer
«interface»
PolicyLayer
Mech
Mechanism
«interface»
MechanismLayer
Util
MechanismLayer
UtilityLayer
Utility
UtilityLayer
EDAF25 (F7)
VT 2015
13 / 44
EDAF25 (F7)
Designprinciper för paket
Designprinciper för paket
Exempel DIP vs SDP
Exempel DIP vs SDP
DIP: Fortfarande beroenden mot instabila paket:
VT 2015
14 / 44
VT 2015
16 / 44
SDP: Beroenden mot stabila paket:
Util
Util
PolicyLayer
PolicyLayer
«interface»
Mech
Util
«interface»
Mech
Util
«interface»
MechanismLayer
MechanismLayer
Util
Util
Util
«interface»
Util
UtilityLayer
UtilityLayer
EDAF25 (F7)
VT 2015
15 / 44
EDAF25 (F7)
Designprinciper för paket
Designprinciper för paket
Stabilitetsmetrik
Stabilitetsmetrik
Paketets stabilitet: S = Ca/(Ce + Ca) , där
Ca är antalet klasser utanför paketet som beror på klasser i paketet. a
står för afferent (inåtriktad).
Ce är antalet klasser i paketet som beror på klasser utanför paketet. e
står för efferent (utåtriktad).
S = 0 innebär inget ansvar, S = 1 innebär inget beroende. Om S = 1
för alla paket i systemet så är det inget system.
Paketets Abstrakthet: A = Na/Nc, där
Na är antalet abstrakta klasser (gränssnitt) i paketet.
Nc är antalet klasser i paketet.
Paketets instabilitet: I = 1 − S = Ce/(Ce + Ca)
I = 0 är ett maximalt stabilt paket. Oberoende paket
EDAF25 (F7)
VT 2015
17 / 44
EDAF25 (F7)
Designprinciper för paket
Designprinciper för paket
Stabilitetsmetrik
Paketstrukturer
18 / 44
Komponenter Paketen är komponenter i systemet. Exempel: memory
och program i Computer.
Ramverk Systemet byggs genom att utvidga klasser i andra paket.
Exempel:
A-I grafen:
A = I = 1 är meningslösa zonen (useless zone)
A = I = 0 är problemzonen (zone of pain)
javax.swing, java.awt. Ett användargränssnitt konstrueras genom att
utvidga och fylla i klasserna i ramverket.
Eclipse.
Observer/Observable
A = 0, I = 1 och A = 1, I = 0 är önskvärda zoner
EDAF25 (F7)
VT 2015
VT 2015
19 / 44
EDAF25 (F7)
VT 2015
20 / 44
Designprinciper för paket
Namngivning
Paketstrukturer
Bra namngivning är fundamental för att göra program begripliga.
Ramverk är mycket svårare att bygga.
Building frameworks
You have to build at least three frameworks and reject them before you can
be reasonably confident that you have build the right archictecture for one
domain.[Paraphrasing Rebecca Wirfs-Brock.]
public class MyList {
private List<int[]> theList;
public List<int[]> getList() {
List<int[]> list = new ArrayList<int[]>();
for (int[] is : theList) {
if (is[0] < 4) {
list.add(is);
}
}
return list;
}
}
Martin: Kapitel 30. Educational Testing Service.
Vad handlar det om?
EDAF25 (F7)
VT 2015
21 / 44
Namngivning
EDAF25 (F7)
VT 2015
22 / 44
VT 2015
24 / 44
Namngivning
Det handlar om projektgrupper.
public class Groups {
private List<Group> groups;
public List<Group> incompleteGroups() {
List<Group> list = new ArrayList<Group>();
for (Group group : groups) {
if (! group.isComplete()) {
list.add(group);
}
}
return list;
}
}
En grupp ska bestå av fyra studenter.
public class Group extends ArrayList<Student> {
private static final int MAXSIZE = 4;
public boolean isComplete() {
return size() >= MAXSIZE;
}
}
I vilka grupper finns det plats för ytterligare studenter?
EDAF25 (F7)
VT 2015
23 / 44
EDAF25 (F7)
Namngivning
Namngivning
Klasser
De reviderade klasserna behöver knappast någon särskild dokumentation.
MyList gör det:
MyList innehåller en lista av grupper av studenter.
En grupp representeras med en “heltalsarray” där det första elementet
innehåller antalet studenter i gruppen och de övriga innehåller
id-nummer för studenterna.
Ett klassnamn är normalt ett substantiv hämtat från uppdragsgivarens
beskrivning eller den verklighet som programmet modellerar.
Namnet inleds med en versal och följs av gemener. På engelska
använder man versal i början på varje ord när namnet är sammansatt.
Metoden getList returnerar en lista med de grupper som har plats för
ytterligare studenter.
EDAF25 (F7)
VT 2015
25 / 44
EDAF25 (F7)
Namngivning
Namngivning
Klasser
Gränssnitt
Konstruera inte klasser som bäst beskrivs med namn som slutar på
Handler, Controller, Manager och liknande. De indikerar ofta dålig
design. Builder och Parser kan vara helt OK för en “fabrik”.
Undvik namn som Item, Element, Value och Data om det inte handlar
om generiska typer.
Undvik att inkludera representationstypen i namnet om typen bara
förekommer i ett attribut.
class StringList extends ArrayList<String>
är OK, medan
VT 2015
26 / 44
Samma principer som för klassnamn.
Namn på gränssnitt används oftare än namn på konkreta klasser;
därför är det viktigare att dessa namn är bra.
Undvik att indikera att det handlar om gränssnitt som i ITree
TreeInterface. Hierarkin som IList, AbstractList och ArrayList är bra
när alla nivåerna behövs.
private String string [];
\\ omissions
}
inte är det.
EDAF25 (F7)
VT 2015
27 / 44
EDAF25 (F7)
VT 2015
28 / 44
Namngivning
Namngivning
Metoder
Attribut, lokala variabler och parametrar
Ett attribut kan ofta ha samma namn som sin typ, fast med inledande
gemen.
Metodnamn inleds med en gemen och följande ord i sammansatta
namn med versal.
Metoder som förändrar objektets tillstånd bör ha ett verb som namn.
Om det finns flera attribut av samma typ som används på samma sätt
kan man numrera dem: Expr expr1, expr2;
Metoder som inte förändrar objektets tillstånd bör ha ett substantiv
som namn eller inledas med is om de implementerar ett predikat.
När en variabel används som index i en “array” använder man gärna
konventionella namn som i och j.
Namn som inleds med set och get bör reserveras för de tillfällen då det
handlar om att sätta och hämta attribut.
För strängar använder man gärna namn som indikerar användningen:
String title;
Använd inte the som ett prefix i attributnamn. När det behövs är this
det självklara alternativet.
EDAF25 (F7)
VT 2015
29 / 44
EDAF25 (F7)
Repetition Observer
Repetition Observer
Tentauppgift
Tentauppgift
VT 2015
30 / 44
VT 2015
32 / 44
I ett ramverk som implementerar designmönstret Observer finns
Implementationen av notifyObservers kan se ut enligt nedan:
public abstract class Observable {
public void addObserver(Observer)
protected void setChanged();
public void notifyObservers()
...
}
public interface Observer {
public void update(Observable observable)
}
Deklarera och initiera lämpliga attribut i Observable och gör en möjlig
implementering av metoden notifyObservers. Det är tillåtet att använda
klassen java.util.Vector med metoderna boolean add(Object) och Iterator
iterator(). Gränssnittet Iterator har bl a metoderna boolean hasNext() och
Object next().
EDAF25 (F7)
VT 2015
31 / 44
public class Observable {
private boolean changed = false;
private List obs = new Vector();
public void notifyObservers() {
if (changed) {
Iterator it = obs.iterator();
while (it.hasNext()) {
((Observer)it.next()).update(this);
}
changed = false;
}
}
}
EDAF25 (F7)
Designmönster
Designmönster
Factory Method
Factory Method tar bort beroendet till de konkreta klasserna
SomeApp
SomeApp
SomeApp har endast beroende
till gränssnittet Shape.
<<interface>>
Shape
Square
SomeApp skapar objekt av
Square och Circle – och får
därmed även beroende till
konkreta klasserna Square och
Circle.
Circle
<<interface>>
Shape Factory
+ makeSquare():Shape
+ makeCircle():Shape
ShapeFactory
Implementation
<<creates>>
EDAF25 (F7)
VT 2015
33 / 44
<<interface>>
Shape
Square
EDAF25 (F7)
Designmönster
Designmönster
Factory Method
Factory Method
Circle
VT 2015
34 / 44
Vad måste nu SomeApp känna till?
SomeApp
Factory method används när man:
<<interface>>
Shape Factory
+ make(String):Shape
ShapeFactory
Implementation
vill undvika beroende av konkreta klasser
<<interface>>
Shape
Square
måste avgöra vilken sorts objekt som skall skapas vid exekveringen
Circle
<<creates>>
EDAF25 (F7)
VT 2015
35 / 44
EDAF25 (F7)
VT 2015
36 / 44
Factory Method
Factory Method
i Computer
Operandfabriken
Factory method används när man:
public class OperandFactory {
public Operand build(String string) {
if(string.charAt(0)==’[’) {
return new Address(Integer.parseInt(
string.substring(1,string.length()-1)));
} else {
return new Word(Integer.parseInt(string));
}
}
}
I Computer skapas operander och instruktioner direkt med
konstruerare.
Man skulle kunna skapa dessa från den externa representation.
Vi gör en fabrik för operander?
och en för instruktioner.
EDAF25 (F7)
VT 2015
37 / 44
EDAF25 (F7)
Factory Method
Factory Method
Instruktionsfabriken
Instruktionsfabriken forts.
VT 2015
38 / 44
VT 2015
40 / 44
Instruktionsfabriken forts.
public class InstructionFactory {
private OperandFactory operandFactory = new OperandFactory();
public Instruction build(String string) {
StringTokenizer tokenizer = new StringTokenizer(string);
Operand op1, op2, op3;
String opCode = tokenizer.nextToken();
if (opCode.equals("ADD")) {
op1 = operandFactory.build(tokenizer.nextToken());
op2 = operandFactory.build(tokenizer.nextToken());
op3 = operandFactory.build(tokenizer.nextToken());
return new Add(op1, op2, (Address) op3);
}
...
} else if (opCode.equals("CPY")) {
op1 = operandFactory.build(tokenizer.nextToken());
op2 = operandFactory.build(tokenizer.nextToken());
return new Copy(op1, (Address) op2);
} else if (opCode.equals("HLT")) {
return new Halt();
} else if ... {
}
else {
throw new RuntimeException("syntax error");
}
}
}
EDAF25 (F7)
VT 2015
39 / 44
EDAF25 (F7)
Repetition
Tentauppgift
Tentauppgift
Lösning
En objektorienterad beskrivning av listor : Det finns två sorters listor:
tomma listor som inte innehåller någonting och icke-tomma listor som
innehåller ett huvud som är av typen Object och en svans som är en lista.
Längden av en tom lista är 0 och längden av en icketom lista är 1 +
längden av svansen.
«interface»
List
Gör ett klassdiagram för denna beskrivning som visar alla relationer och
med en metod för att beräkna längden av en lista. (Ignorera allt du vet om
länkade listor!) Implementera klasserna.
Empty
Cons
I klassdiagrammet skall du använda konventionella engelska benämningar:
lista = list, tom = empty, icketom = cons, huvud = head, längd = length
och svans = tail. Namn på Java-klasser inleds med versal.
Object
Rita ett objektdiagram för listan i exemplet.
EDAF25 (F7)
VT 2015
EDAF25 (F7)
41 / 44
Tentauppgift
Tentauppgift
Lösning
Lösning
public interface List {
public int length() ;
}
public class Empty implements List {
public int length() {
return 0;
}
}
public class Cons implements List {
Object head;
List tail;
public int length() {
return 1+tail.length();
}
}
EDAF25 (F7)
VT 2015
43 / 44
VT 2015
:Cons
:Cons
”A”:String
”B”:String
EDAF25 (F7)
42 / 44
:Empty
VT 2015
44 / 44