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