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
© Copyright 2024