Objektorienterad modellering och design (EDAF25) Föreläsning 5 Repetition Grafer Traversering bredden först med kö Agenda 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å. 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(); EDAF25 (F5) VT 2015 1 / 57 Grafer Repetition Lab3 Bredden först EDAF25 (F5) VT 2015 2 / 57 Designmönster - Repetition 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 FileMenuItem action(storage, String) dialogkind() LoadMenuItem SaveMenuItem EDAF25 (F5) VT 2015 3 / 57 EDAF25 (F5) VT 2015 4 / 57
Designmönster - Repetition Strategy Lab3 Designmönster Repetition Singleton WLGraph «interface» GraphStrategy + adjacent(string,string): boolean OneLetterDifference 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 EDAF25 (F5) VT 2015 5 / 57 Designmönster EDAF25 (F5) VT 2015 6 / 57 Designmönster Command Composite Template Method Strategy Singleton Null Object Facade Decorator EDAF25 (F5) VT 2015 7 / 57 EDAF25 (F5) VT 2015 8 / 57
Designmönster problemet med null Designmönster 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; :Node :Node :Node EDAF25 (F5) 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 Programkoden blir enklare om man istället använder ett riktigt objekt. Detta är ett exempel på mönstret Null Object. Objektorienterad beskrivning: 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. NullEmployee «Interface» Employee EmployeeImplementation EDAF25 (F5) VT 2015 13 / 57 Designmönster Null Object Lista med objektorienterad representation EDAF25 (F5) VT 2015 14 / 57 Designmönster Null Object 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(); Empty «Interface» List Node Man ersätter iteration med rekursion; det gör programmet logiskt enklare; testet av det logiska villkoret i while-satsen försvinner. I nästan alla sammanhang är det bra design att representera något som är tomt med ett riktigt objekt. EDAF25 (F5) VT 2015 15 / 57 EDAF25 (F5) VT 2015 16 / 57
Payroll - fallstudie Systembeskrivning Payroll - fallstudie 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. 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 17 / 57 Payroll - fallstudie 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 övergripande design kapitel 18 i Martin Implementering kapitel 19 i Martin med C++. Implementering med Java i Payroll.zip via föreläsningssidan EDAF25 (F5) VT 2015 19 / 57 EDAF25 (F5) VT 2015 20 / 57
Payroll - fallstudie Databasen enligt Martin Designmönster Facade Databasen är en implementeringsdetalj. Moduler skall bero på abstraktioner (DIP). Definiera ett gränssnitt (API)! Employee DB + get(int): Employee + put(int, Employee): Employee + remove(int): Employee Application Generic DB + <many generic methods> + EDAF25 (F5) VT 2015 21 / 57 Designmönster Facade EDAF25 (F5) VT 2015 22 / 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) VT 2015 24 / 57
Payroll fallstudie Employee Det finns tre sorters anställda Payroll fallstudie 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 Payroll Fallstudie Strategy EDAF25 (F5) VT 2015 26 / 57 Payroll Fallstudie Employe 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) VT 2015 28 / 57
Designmönster Decorator Designmönster Decorator Skånetrafiken vill få en lista på alla köp av biljetter under oktober. Standardautomaten: 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; Den nya funktionaliteten: 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); EDAF25 (F5) VT 2015 29 / 57 Designmönster Decorator EDAF25 (F5) VT 2015 30 / 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) VT 2015 32 / 57
Projektet Computer Specifikation Projektet Computer Test public class Computer { public Computer(Memory memory) public void load(program program) public void run() 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(); EDAF25 (F5) VT 2015 33 / 57 Projektet Computer Testprogrammet Factorial EDAF25 (F5) VT 2015 34 / 57 Projektet Computer 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()); 0 CPY 5 [0] 1 CPY 1 [1] 2 JEQ 6 [0] 1 3 MUL [1] [0] [1] 4 ADD [0] -1 [0] 5 JMP 2 6 PRT [1] 7 HLT 120 EDAF25 (F5) VT 2015 35 / 57 EDAF25 (F5) VT 2015 36 / 57
Projektet Computer Genomförande Projektet Computer Genomförande Redovisningstider och rum ligger på hemsidan under Gruppindelning" Registrera er grupp (alla gruppmedlemmar) på önskad redovisningtid Gruppen: 1 formulerar svaren på åtta frågor 2 gör en design med klass- och sekvensdiagram 3 skickar in klassdiagram (24 timmar före mötet) 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). 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. Ett objekt vars tillstånd inte kan förändras kallas omuterbart (immutable). 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 Exempel Muterbara vs ej muterbara objekt En omuterbar klass: En omuterbar klass: public final class Num implements Expr { private int value; public value() { return value; En muterbar klass: public class Counter { private int counter; public increment() { counter++; Recept för omuterbarhet Klassen bör vara final. Attributen måste vara privata. Attributen får ej vara muterbara. Inga metoder får förända attribut. Fördelar: Säkrare Behöver ej kopieras, kan delas Enklare att resonera om EDAF25 (F5) VT 2015 41 / 57 Muterbara vs ej muterbara objekt Aktivitet EDAF25 (F5) VT 2015 42 / 57 Muterbara vs ej muterbara objekt Aktivitet lösning public final class SafeContainer { private final Object object; public SafeContainer(Object object) { this.object = object; public String tostring() { return object.tostring(); 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) VT 2015 44 / 57
Designprinciper ISP Segregation Designprinciper Java.util.Collection Interface Segregation Principle Classes should not be forced to depend on methods that they do not use. 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) VT 2015 45 / 57 Designprinciper Collection javadoc EDAF25 (F5) VT 2015 46 / 57 Designprinciper 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] Alla som implementerar gränssnittet måste ha metoder som inte behöver fungera. Hur borde det se ut? EDAF25 (F5) VT 2015 47 / 57 EDAF25 (F5) VT 2015 48 / 57
Designprinciper ISP Hur borde det se ut? Designprinciper ISP 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(); 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(); EDAF25 (F5) VT 2015 49 / 57 Designprinciper ISP Vad tycker Josh och Neal? Repetition EDAF25 (F5) VT 2015 50 / 57 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 Integritetsprincipen Gör attribut, metoder och klasser så hemliga de går. 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 Integritetsprincipen Exponera inte representationen: public class Figure extends ArrayList<Shape> { public void paint(graphics graphics) { for (Shape shape : this) { shape.paint(graphics); Ej exponerad public class Figure { private List<Shape> list = new ArrayList<Shape>(); public void paint(graphics graphics) { for (Shape shape : list) { shape.paint(graphics); Repetition Integritetsprincipen 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; EDAF25 (F5) VT 2015 53 / 57 Repetition Spekulativ design EDAF25 (F5) VT 2015 54 / 57 Repetition Spekulativ design Exempel Fool me once shame on you Fool me twice shame on me. 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. Uppdragsgivaren vill ha en lista av Item-objekt: Take the first bullet and protect yourself from the second bullet from the same gun. EDAF25 (F5) VT 2015 55 / 57 EDAF25 (F5) VT 2015 56 / 57
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