Lecture 4-ht15.pptx

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