Objektorienterad modellering och design (EDAF25) Repetition
Transcription
Objektorienterad modellering och design (EDAF25) Repetition
Objektorienterad modellering och design (EDAF25) Repetition Grafer Föreläsning 5 Traversering bredden först med kö Agenda public void breadthFirst(Vertex v){ v.visited = true; //Gör något med noden q.add(v); while (!q.isEmpty()){ Vertex x = q.remove; Edge e = x.firstEdge(); while (e != null){ Vertex w = endPoint(); if (!w.visited){ w.visited = true; //Gör något med noden; q.add(w); } e = e.nextEdge(); } } } Repetition (Grafer, Designmönster, Designprinciper) Designmönster (Null Object, Facade, Decorator) Introduktion av Payroll fallstudien Interface Segregation Principle ISP Introduktion av projekt 1 Muterbar vs ej muterbar Att göra de närmaste veckorna: lab 3 redovisas på fredag! 2 veckor undervisningsfritt p.g.a. tentor Övning 2 redovisas fredagen därpå. EDAF25 (F5) VT 2015 1 / 57 EDAF25 (F5) Grafer Repetition Designmönster - Repetition Lab3 – Bredden först Template distance = 0 markera u besökt actlevel = tom mängd lägg in u i actlevel så länge actlevel inte är tom nextlevel = tom mängd för varje nod w i actlevel om w == v returnera distance för varje granne n till w om n inte är besökt markera n besökt lägg in n i nextlevel distance++; actlevel = nextlevel returnera -1 EDAF25 (F5) VT 2015 2 / 57 VT 2015 4 / 57 FileMenuItem action(Storage, String) dialogKind() LoadMenuItem VT 2015 3 / 57 EDAF25 (F5) SaveMenuItem Designmönster - Repetition Designmönster – Repetition Strategy – Lab3 Singleton public class Singleton { private static Singleton instance; // attributes omitted private Singleton() { // omissions } public static Singleton instance() { if (instance == null) { instance = new Singleton(); } return instance; } // other methods omitted } «interface» WLGraph GraphStrategy + adjacent(String,String): boolean OneLetterDifference EDAF25 (F5) VT 2015 5 / 57 Designmönster EDAF25 (F5) VT 2015 6 / 57 VT 2015 8 / 57 Designmönster Command Composite Null Object Template Method Facade Strategy Decorator Singleton EDAF25 (F5) VT 2015 7 / 57 EDAF25 (F5) Designmönster Designmönster problemet med null problemet med null public class Node { private Object object; private Node next; } public class List { private Node first; public int length() { int length = 0; Node node = first; while (node != null) { length++; node = node.next(); } return length; } } EDAF25 (F5) :Node :Node :Node VT 2015 9 / 57 Designmönster EDAF25 (F5) VT 2015 10 / 57 Designmönster problemet med null Introduktionen av null i objektorienterade språk var ett fundamentalt misstag. null modellerar något som inte finns. Länkade listor och träd avslutas ofta med null. Null är inget objekt; att använda null för att representera “ingenting” är ett exempel på icke-objektorienterad programmering. EDAF25 (F5) VT 2015 11 / 57 EDAF25 (F5) VT 2015 12 / 57 Designmönster – Null Object Designmönster – Null Object «Interface» Employee Programkoden blir enklare om man istället använder ett riktigt objekt. Detta är ett exempel på mönstret Null Object. Objektorienterad beskrivning: NullEmployee En lista är antingen tom eller består av en nod med ett element som är ett Object och en svans som är en lista. EmployeeImplementation EDAF25 (F5) VT 2015 13 / 57 EDAF25 (F5) Designmönster – Null Object Designmönster – Null Object Lista med objektorienterad representation Objektorienterad listimplementering public interface List { public int length(); } public class Empty implements List { public int length() { return 0; } } public class Node implements List{ private Object object; private List tail; public int length() { return 1 + tail.length(); } } EDAF25 (F5) VT 2015 14 / 57 Man ersätter iteration med rekursion; det gör programmet logiskt enklare; testet av det logiska villkoret i while-satsen försvinner. «Interface» List I nästan alla sammanhang är det bra design att representera något som är tomt med ett riktigt objekt. Empty Node VT 2015 15 / 57 EDAF25 (F5) VT 2015 16 / 57 Payroll - fallstudie Payroll - fallstudie Systembeskrivning Systembeskrivning Vissa anställda arbetar på timbasis. Deras timlön finns i anställningsposten. De lämnar in tidkort med datum och antal timmar. Lönen utbetalas fredagar. Vissa anställda har fast lön som utbetalas sista vardagen varje månad. Vissa anställda med fast lön får också provision baserad på kvitton med datum och belopp med löneutbetalning varannan fredag. Lön utbetalas antingen via postanvisning till angiven adress, direkt till konto på bank, eller avhämtas på lönekontoret. EDAF25 (F5) VT 2015 17 / 57 Payroll - fallstudie Vissa anställda tillhör fackföreningen. Deras anställningskort innehåller veckoavgift. Föreningen kan debitera serviceavgifter för enskilda medlemmar. Avgifter dras från nästa lön. Transaktioner till systemet behandlas en gång om dagen och uppdaterar en databas. Löneutbetalningar genereras varje avlöningsdag. EDAF25 (F5) VT 2015 18 / 57 Payroll - fallstudie Martins bok Användningsfall 1 Lägg till en ny anställd. 2 Ta bort en anställd 3 Registrera ett tidkort 4 Registrera ett försäljningskvitto 5 Registrera en föreningsavgift 6 Ändra anställningsinformation 7 Generera löneutbetalningar EDAF25 (F5) övergripande design – kapitel 18 i Martin Implementering – kapitel 19 i Martin med C++. Implementering med Java i Payroll.zip via föreläsningssidan VT 2015 19 / 57 EDAF25 (F5) VT 2015 20 / 57 Payroll - fallstudie Designmönster – Facade Databasen enligt Martin Employee Databasen är en implementeringsdetalj. Moduler skall bero på abstraktioner (DIP). DB + get(int): Employee + put(int, Employee): Employee + remove(int): Employee Application Definiera ett gränssnitt (API)! Generic DB + <many generic methods> +… EDAF25 (F5) VT 2015 21 / 57 Designmönster – Facade EDAF25 (F5) VT 2015 22 / 57 VT 2015 24 / 57 Designmönster – Facade Databas – implementering för testning public interface Database { public Employee put(int key, Employee employee); public Employee get(int key); public Employee remove(int key); } public class TestDatabase implements Database { private Map<Integer, Employee> employees = new HashMap<Integer, Employee>(); public Employee get(int empId) { return employees.get(empId); } public Employee remove(int empId) { return employees.remove(empId); } public Employee put(int empId, Employee employee) { return employees.put(empId, employee); } } EDAF25 (F5) VT 2015 23 / 57 EDAF25 (F5) Payroll – fallstudie Payroll – fallstudie Employee – Det finns tre sorters anställda Användningsfall: en timanställd blir löneanställd Design utan eftertanke Om en timanställd blir löneanställd så måste man skapa ett nytt objekt och kopiera data från det gamla. Bättre design? Designmönster? Vad är problemet? EDAF25 (F5) VT 2015 25 / 57 EDAF25 (F5) Payroll – Fallstudie Payroll – Fallstudie Strategy Employe VT 2015 26 / 57 VT 2015 28 / 57 Anställningsformen är en strategi Employee - name: String - address: String - id: int «interface» Classification SalaryClassification SalaryClassification SalaryClassification EDAF25 (F5) VT 2015 27 / 57 EDAF25 (F5) Designmönster – Decorator Designmönster – Decorator Skånetrafiken vill få en lista på alla köp av biljetter under oktober. Den nya funktionaliteten: Standardautomaten: public LoggingPayStation implements PayStation { private PayStation payStation; private List<String> log; public LoggingPayStation(PayStation payStation, List<String> log) { this.payStation = payStation; this.log = log; } public double pay(TravelCard travelCard, int zones) { log.add(travelCard.toString() + zones); return payStation.pay(travelCard, zones); } } public interface PaySation { public double pay(TravelCard travelCard, int zones); } public StandardPayStation implements PayStation { private double sum; public double pay(TravelCard travelCard, int zones) { double price = travelCard.price(zones); sum += price; return price; } } EDAF25 (F5) VT 2015 29 / 57 Designmönster – Decorator EDAF25 (F5) VT 2015 30 / 57 VT 2015 32 / 57 Designmönster – Decorator Loggningen kan göras dynamiskt PayStation standardPayStation = new StandardPayStation(); PayStation payStation = standardPayStation; I början av oktober lägger vi till loggningen: payStation = new LoggingPayStation(standardPayStation); I slutet av oktober tar vi bort den: payStation = standardPaystation; Tillståndet i standardPayStation bevaras. EDAF25 (F5) VT 2015 31 / 57 EDAF25 (F5) Projektet Computer Projektet Computer Specifikation Test public static void main(String[] args) { Program factorial = new Factorial(); System.out.println(factorial); Computer computer = new Computer(new LongMemory(64)); computer.load(factorial); computer.run(); } public class Computer { public Computer(Memory memory) public void load(Program program) public void run() } EDAF25 (F5) VT 2015 33 / 57 EDAF25 (F5) Projektet Computer Projektet Computer Testprogrammet Factorial Utskrift public class Factorial extends Program { public Factorial() { Address n = new Address(0), fac = new Address(1); add(new Copy(new LongWord(5), n)); add(new Copy(new LongWord(1), fac)); add(new JumpEq(6, n, new LongWord(1))); add(new Mul(fac, n, fac)); add(new Add(n, new LongWord(-1), n)); add(new Jump(2)); add(new Print(fac)); add(new Halt()); } } EDAF25 (F5) 0 1 2 3 4 5 6 7 CPY CPY JEQ MUL ADD JMP PRT HLT VT 2015 34 / 57 VT 2015 36 / 57 5 [0] 1 [1] 6 [0] 1 [1] [0] [1] [0] -1 [0] 2 [1] 120 VT 2015 35 / 57 EDAF25 (F5) Projektet Computer Projektet Computer Genomförande Genomförande Gruppen: 1 formulerar svaren på åtta frågor 2 gör en design med klass- och sekvensdiagram Redovisningstider och rum ligger på hemsidan under ”Gruppindelning" 3 skickar in klassdiagram (24 timmar före mötet) Registrera er grupp (alla gruppmedlemmar) på önskad redovisningtid 4 förbereder en 3-minuters muntlig presentation av gruppens design 5 tar med sekvensdiagram och träffar sin handledare för designmöte (10 april) 6 reviderar designen och implementerar 7 skickar in klassdiagram och källkod (senast 17 april) Merparten av projekttiden brukar behövas för designen. EDAF25 (F5) VT 2015 37 / 57 Muterbara vs ej muterbara objekt EDAF25 (F5) VT 2015 38 / 57 Muterbara vs ej muterbara objekt Ett objekt vars tillstånd kan förändras kallas muterbart (mutable). Ett objekt vars tillstånd inte kan förändras kallas omuterbart (immutable). När objektet modellerar någonting i verkligheten som har ett tillstånd som kan förändras så är det rimligt att modellen har samma egenskap. När ett objektet modellerar någonting i verkligheten vars tillstånd inte kan förändras så är det rimligt att modellen har samma egenskap. Integer-objekt och String-objekt är omuterbara. EDAF25 (F5) VT 2015 39 / 57 EDAF25 (F5) VT 2015 40 / 57 Muterbara vs ej muterbara objekt Muterbara vs ej muterbara objekt Exempel En omuterbar klass: Recept för omuterbarhet En omuterbar klass: public final class Num implements Expr { private int value; public value() { return value; } } Klassen bör vara final. Attributen måste vara privata. Attributen får ej vara muterbara. Inga metoder får förända attribut. En muterbar klass: Fördelar: Säkrare public class Counter { private int counter; public increment() { counter++; } } EDAF25 (F5) Behöver ej kopieras, kan delas Enklare att resonera om VT 2015 41 / 57 EDAF25 (F5) Muterbara vs ej muterbara objekt Muterbara vs ej muterbara objekt Aktivitet Aktivitet – lösning public final class SafeContainer { private final Object object; public SafeContainer(Object object) { this.object = object; } public String toString() { return object.toString(); } } VT 2015 42 / 57 VT 2015 44 / 57 List<String> list = new ArrayList<String>(); SafeContainer safeContainer = new SafeContainer(list); list.add("string"); Klassen SafeContainer är muterbar. Är klassen muterbar? EDAF25 (F5) VT 2015 43 / 57 EDAF25 (F5) Designprinciper – ISP Designprinciper Segregation Java.util.Collection Interface Segregation Principle Classes should not be forced to depend on methods that they do not use. EDAF25 (F5) VT 2015 45 / 57 public interface Collection<E> extends Iterable<E> { int size(); boolean isEmpty(); boolean contains(Object o); Iterator<E> iterator(); Object[ ] toArray(); <T> T[ ] toArray(T[ ] a); boolean add(E e); boolean remove(Object o); boolean containsAll(Collection<?> c); boolean addAll(Collection<? extends E> c); boolean removeAll(Collection<?> c); void clear(); boolean equals(Object o); int hashCode(); } EDAF25 (F5) Designprinciper Designprinciper Collection javadoc Collection bryter mot ISP The “destructive” methods contained in this interface, that is, the methods that modify the collection on which they operate, are specified to throw UnsupportedOperationException if this collection does not support the operation. If this is the case, these methods may, but are not required to, throw an UnsupportedOperationException if the invocation would have no effect on the collection. For example, invoking the addAll(Collection) method on an unmodifiable collection may, but is not required to, throw the exception if the collection to be added is empty. [Josh Bloch, Neal Gafter] EDAF25 (F5) VT 2015 47 / 57 VT 2015 46 / 57 Alla som implementerar gränssnittet måste ha metoder som inte behöver fungera. Hur borde det se ut? EDAF25 (F5) VT 2015 48 / 57 Designprinciper – ISP Designprinciper – ISP Hur borde det se ut? Hur borde det se ut? public interface Collection<E> extends Iterable<E> { int size(); boolean isEmpty(); boolean contains(Object o); Iterator<E> iterator(); Object[ ] toArray(); <T> T[ ] toArray(T[ ] a); boolean containsAll(Collection<?> c); boolean equals(Object o); int hashCode(); } EDAF25 (F5) public interface ImmutableCollection<E> extends Collection<E> {} public interface MutableCollection<E> extends Collection<E> { boolean add(E e); boolean remove(Object o); boolean addAll(Collection<? extends E> c); boolean removeAll(Collection<?> c); void clear(); } VT 2015 49 / 57 Designprinciper – ISP EDAF25 (F5) VT 2015 50 / 57 Repetition Vad tycker Josh och Neal? Integritetsprincipen Gör attribut, metoder och klasser så hemliga de går. Jag tror att de håller med. De har skrivit en bok som visar att Java har många brister och konstigheter. Joshua Bloch, Neal Gafter: Java Puzzlers ? Traps, pitfalls, and corner cases. Addison-Wesley, 2005, ISBN 0-321-33678-X. Länk: www.javapuzzlers.com Lämna inte ut representationen i onödan. En klass skall inte ha tillgång till klasser som den inte behöver. Begränsa synligheten genom att använda : private – bara klassen kan se paketsynlighet – klasser i paketet kan se protected – subklasser och klasser i paketet kan se. public – hela världen kan se. EDAF25 (F5) VT 2015 51 / 57 EDAF25 (F5) VT 2015 52 / 57 Repetition Repetition Integritetsprincipen Integritetsprincipen Exponera inte representationen: public class Figure extends ArrayList<Shape> { public void paint(Graphics graphics) { for (Shape shape : this) { shape.paint(graphics); } } } Utlämnad representation: public class Figure { private List<Shape> list; public void paint(Graphics graphics) { for (Shape shape : list) { shape.paint(graphics); } } public List<Shape> list() return list; } } Ej exponerad public class Figure { private List<Shape> list = new ArrayList<Shape>(); public void paint(Graphics graphics) { for (Shape shape : list) { shape.paint(graphics); } } } EDAF25 (F5) VT 2015 53 / 57 EDAF25 (F5) Repetition Repetition – Spekulativ design Spekulativ design Exempel VT 2015 54 / 57 VT 2015 56 / 57 Fool me once – shame on you Fool me twice – shame on me. Uppdragsgivaren vill ha en lista av Item-objekt: Skriv program som om förutsättningarna inte kommer att förändras. Om detta ändå sker så implementera abstraktioner som skyddar mot framtida förändringar av samma slag. Take the first bullet – and protect yourself from the second bullet from the same gun. EDAF25 (F5) VT 2015 55 / 57 EDAF25 (F5) Repetition – Spekulativ design Exempel Uppdragsgivaren vill senare ha en lista som innehåller Item1-objekt och Item2-objekt. Detta är första skottet; nu garderar vi oss mot ett liknande skott: EDAF25 (F5) VT 2015 57 / 57