15-09-10 Objektorienterad modellering och diskreta strukturer (EDAF10/EDA061) HT1 2015, FÖRELÄSNING 4 Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund Förra föreläsningen • Designmönster: – Command – Composite – Template Method – Strategy • UML: Objekt- och Sekvensdiagram • Projektet Computer Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund EDAF10/EDA061 HT2014, Ulf Asklund 1 15-09-10 Dagens agenda • Designmönster – Strategy (repetition och exempel) – Singleton – Null object – Facade – Decorator • ISP – Interface Segregation Principle • Muterbar vs. Ej muterbar • Intro till Payroll Ø Hur går övningarna? Ø Projektgrupp klar och redovisningstid inbokad?! Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund Lista med utskrift public class List<T> extends ArrayList<T> { public String toString() { StringBuilder builder = new StringBuilder(); for (T t : this) { builder.append(t).append(’\n’); } return builder.toString(); } public String toStringStar() { StringBuilder builder = new StringBuilder(); for (T t : this) { builder.append(”*”); builder.append(t).append(’\n’); } return builder.toString(); } } Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund EDAF10/EDA061 HT2014, Ulf Asklund 2 15-09-10 Strategy Först själva listan: public class List<T> extends ArrayList<T> { private Prefix prefix = new Empty(); public void setPrefix(Prefix prefix) { this.prefix = prefix; } } public String toString() { StringBuilder builder = new StringBuilder(); for (T t : this) { builder.append(prefix.string()); builder.append(t).append(’\n’); } return builder.toString(); } Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund Strategiklasserna public interface Prefix { public String string(); } public class Empty implements Prefix { public String string() { return ””; } } public class Star implements Prefix { public String string() { return ”∗ ”; } } public class Numbered implements Prefix { private int number; public String string() { number++; return String.valueOf(number) + ” ”; } Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund } EDAF10/EDA061 HT2014, Ulf Asklund 3 15-09-10 Jojo-kort med två strategier public class TravelCard { private Tariff tariff; //Strategy public void setTariff(Tariff tariff) { this.tariff = tariff; } public double price(int zones, Rebate rebate) { double amount = tariff.price(zones); return rebate.price(amount); } } Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund Två strategi-interface public interface Tariff { public double price(int zones); } public interface Rebate { public double price(double price); } Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund EDAF10/EDA061 HT2014, Ulf Asklund 4 15-09-10 Två strategier public class Skane implements Tariff { public double price(int zones) { switch (zones) { case 1: return 17.0; default: return 7.0 * zones + 7.0; } } } public class Family implements Rebate { public double price(double price) { return 1.5 *price; } } Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund Strategierna har inget tillstånd public final static Tariff SKANE = new Skane(); public final static Rebate DUO = new Family(); ... TravelCard jojo = new TravelCard(); jojo.setTariff(SKANE); double price = jojo.price(3, DUO); Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund EDAF10/EDA061 HT2014, Ulf Asklund 5 15-09-10 Template method eller Strategy? Båda mönstren kan användas för att eliminera duplicerad kod. Använd Template method när funktionaliteten skall vara den samma under objektets hela livstid. Använd Strategy när funktionaliteten skall kunna förändras under livstiden eller när det finns mer än en funktionalitet som kan variera. Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund Singleton • Syfte: att det bara skall kunna skapas en instans av klass • ”Hackerns” (en som inte följer principer) favoritmönster Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund EDAF10/EDA061 HT2014, Ulf Asklund 6 15-09-10 Konventionell Singleton public class Singleton { private static Singleton instance = null; // other attributes omitted private Singleton() { // omissions } public static Singleton instance() { if (instance == null) { instance = new Singleton(); } } } return instance; // other methods omitted Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund Singleton • Subklasser till en Singleton är inte automatiskt en Singleton • Bieffekt av den konventionella implementeringen: instansen blir ett globalt åtkomligt objekt. • Globala objekt är bekväma att använda men innebär i regel dålig design. På nästa övning skall vi implementera Singleton-mönstret utan att skapa globalt tillgängliga objekt. Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund EDAF10/EDA061 HT2014, Ulf Asklund 7 15-09-10 Konventionell länkad lista public class Node { private Object object; private Node next; public Node next() { return 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; } NULL • Detta är en maskerad form av instanceof. • next() är en getter. • Node saknar intelligens. Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund EDAF10/EDA061 HT2014, Ulf Asklund 8 15-09-10 Den skyldige: Tony Hoare Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund Null Object • 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. Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund EDAF10/EDA061 HT2014, Ulf Asklund 9 15-09-10 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. Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund Objektorienterad representation 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(); } Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund EDAF10/EDA061 HT2014, Ulf Asklund 10 15-09-10 Objektorienterad listimplementering • 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. Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund ISP - Segregation Interface Segregation Principle Classes should not be forced to depend on methods that they do not use. Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund EDAF10/EDA061 HT2014, Ulf Asklund 11 15-09-10 Java.util.Collection 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(); } Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund Collection javadoc 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] Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund EDAF10/EDA061 HT2014, Ulf Asklund 12 15-09-10 Collection bryter mot ISP Alla som implementerar gränssnittet måste ha metoder som inte behöver fungera. Hur borde det se ut? Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund 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(); } Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund EDAF10/EDA061 HT2014, Ulf Asklund 13 15-09-10 Hur borde det se ut? 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(); } Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund Vad tycker Josh och Neal? • 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 Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund EDAF10/EDA061 HT2014, Ulf Asklund 14 15-09-10 Kort repetition Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund 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. Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund EDAF10/EDA061 HT2014, Ulf Asklund 15 15-09-10 Exponera inte representationen Exponerad: 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); } } } Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund Exponera inte representationen, forts. 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; } Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund EDAF10/EDA061 HT2014, Ulf Asklund 16 15-09-10 (nästan) Förbud • instanceof • static • getters Men det finns tillfällen när instanceof, static och getters är nödvändiga och det enda rätta: ... Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund instanceof public final class Integer extends Number implements Comparable<Integer> { private final int value; public boolean equals(Object object) { if(object instanceof Integer) { Integer other = (Integer) object; return value == other.value; } return false; } } // omissions Här finns inget bättre sätt. Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund EDAF10/EDA061 HT2014, Ulf Asklund 17 15-09-10 …2D-punkter… (från första föreläsningen) public class Point2d implements Point { private double x, y; public double distanceTo(Point point) { Point2d other = (Point2d) point; double dx = this.x − other.x; double dy = this.y − other.y; return Math.sqrt(dx ∗ dx + dy ∗ dy); } } Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund static public static main(String arg[]) public final static double PI public static double sin(double a) public class Outer { private static class Inner { } } Språkets design kräver static main. Ibland finns det inget tillhörande objekt. Inre klasser bör helst vara static. Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund EDAF10/EDA061 HT2014, Ulf Asklund 18 15-09-10 getters • Det finns ett exempel i Computer-projektet där en getter ger en bättre helhetsdesign. • Observer-mönstret behöver i regel getters. Ibland måste man kompromissa när principerna drar åt olika håll. Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund Spekulativ design • 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. • Take the first bullet — • and protect yourself from the second bullet from the same gun. Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund EDAF10/EDA061 HT2014, Ulf Asklund 19 15-09-10 Exempel Uppdragsgivaren vill ha en lista av Item-objekt: Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund Exempel, forts. Uppdragsgivaren vill senare ha en lista som innehåller Item1objekt och Item2-objekt. Detta är första skottet; nu garderar vi oss mot ett liknande skott: Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund EDAF10/EDA061 HT2014, Ulf Asklund 20 15-09-10 TANSTAAFL TANSTAAFL There ain’t no such thing as a free lunch. (Martin, sidan 319) Att införa ett designmönster är inte gratis. Det måste finnas ett bra skäl att använda det. T ex så använder man inte strategimönstret om det inte finns minst två strategier. Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund Muterbart vs. Ej muterbart Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund EDAF10/EDA061 HT2014, Ulf Asklund 21 15-09-10 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. Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund Muterbara vs. Ej muterbara objekt, forts 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. Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund EDAF10/EDA061 HT2014, Ulf Asklund 22 15-09-10 Exempel 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++; } Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund Recept för omutbarhet • Klassen måste 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 Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund EDAF10/EDA061 HT2014, Ulf Asklund 23 15-09-10 Aktivitet public final class SafeContainer { private final Object object; public SafeContainer(Object object) { this.object = object; } } public String toString() { return object.toString(); } Är klassen muterbar? Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund Payroll - fallstudie Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund EDAF10/EDA061 HT2014, Ulf Asklund 24 15-09-10 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. Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund Systembeskrivning • 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. Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund EDAF10/EDA061 HT2014, Ulf Asklund 25 15-09-10 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 Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund Use case diagram Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund EDAF10/EDA061 HT2014, Ulf Asklund 26 15-09-10 Use case diagram med arv Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund Martins bok • övergripande design – kapitel 18 i Martin • Implementering – kapitel 19 i Martin med C++. • Implementering med Java i Payroll.zip via föreläsningssidan. Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund EDAF10/EDA061 HT2014, Ulf Asklund 27 15-09-10 Databasen enligt Martin • Databasen är en implementeringsdetalj. • Moduler skall bero på abstraktioner (DIP). • Definiera ett gränssnitt (API) ! Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund Facade-mönstret Employee DB + get(int): Employee + put(int, Employee): Employee + remove(int): Employee Application Generic DB + <many generic methods> +… Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund EDAF10/EDA061 HT2014, Ulf Asklund 28 15-09-10 Designmönster - Facade Designmönster: Mediator (läs i boken) Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund 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); } Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund EDAF10/EDA061 HT2014, Ulf Asklund 29 15-09-10 Employee - Det finns tre sorters anställda Design utan eftertanke Vad är problemet? Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund Användningsfall: en timanställd blir löneanställd • Vad är problemet? 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? Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund EDAF10/EDA061 HT2014, Ulf Asklund 30 15-09-10 Strategy • Anställningsformen är en strategi Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund Employee Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund EDAF10/EDA061 HT2014, Ulf Asklund 31 15-09-10 Decorator-mönstret 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; } Nu vill Skånetrafiken under vissa tider kunna logga vilket kort som används och antal zoner för varje köp. HUR? Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund Decorator-mönstret 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); } Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund EDAF10/EDA061 HT2014, Ulf Asklund 32 15-09-10 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. Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund Decorator-mönstret i Reader-klasserna reader = new BufferedReader(new FileReader(fileName)); public class BufferedReader extends Reader { private Reader in; // omissions } Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund EDAF10/EDA061 HT2014, Ulf Asklund 33 15-09-10 Decorator Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund EDAF10/EDA061 HT2014, Ulf Asklund 34
© Copyright 2024