ht2 2015, fÖrelÄsning15 (xl-projektet...
TRANSCRIPT
EDAF10/EDA061 HT2015, Ulf Asklund 1
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
Objektorienterad modellering och diskreta strukturer (EDAF10)HT2 2015, FÖRELÄSNING 15 (XL-PROJEKTET)
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
Dagens agenda
• Introduktion till projekt 2 (”XL”) – EDA061
• Repetition– MVC-mönstret (Observer-mönstret)
– Factory Method-mönstret– Felhantering
• Glöm inte skapa grupp och boka redovisningstid
EDAF10/EDA061 HT2015, Ulf Asklund 2
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
Vecka 1-3Vecka EDAF101 Föreläsning XL
XL design
2 XL redovisningsmöte 1XL implementation
3 XL implementationXL redovisningsmöte 2
4 XL slutinlämning (vid behov)
• Möte 1: användningsfall, paketindelning, klassdiagram– 3 min presentation
• Möte 2: klassdiagram, källkod (fungerande program), kort beskrivning
– 3 min presentation
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
Projekt 2 – ”XL”
EDAF10/EDA061 HT2015, Ulf Asklund 3
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
Projekt 2 - XL
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
GUI-modellering
Den oerfarne gör allt i en stor klass.
Den agile gör lite i många klasser med beaktande av principen om enkelt ansvar.
EDAF10/EDA061 HT2015, Ulf Asklund 4
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
Paketexpr aritmetiska uttryck – modifieras ej
gui användargränssnittet – modifieras
menu menyer – modifieras
… egna paket
util ”avvecklingspaket”
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
Paketet exprExpr ExprParser
Num
Add
…
AddressExpr
EDAF10/EDA061 HT2015, Ulf Asklund 5
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
Paketet guiGui med mainGuiList
CurrentViewStatusArea
EditorRowNumberPanel
SheetViewSlotView
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
Varför inte javax.swing.Jtable?JTable tillhandahåller mycket som skulle göra projektet lättare, men
döljer mycket av det som projektet vill lära ut
javadoc omfattar 68+ sidor
EDAF10/EDA061 HT2015, Ulf Asklund 6
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
Paketet menu - menyerna
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
Paketet utilAddress
Environment
Adjustment
NumberAdjustment
XLException
XLBufferedReader
XLPrintStream
En del av dessa klasser bör flyttas till andra paket.
EDAF10/EDA061 HT2015, Ulf Asklund 7
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
XL - GuiJFrame ger ett eget fönster på skärmen.
import javax.swing.JFrame; import java.awt.BorderLayout; public class Gui extends JFrame{
public Gui(int count) {super("Untitled-" + count); setLayout(newBorderLayout()); // omissionspack(); setVisible(true);
} }
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
BorderLayout
EDAF10/EDA061 HT2015, Ulf Asklund 8
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
Structure
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
Structure
EDAF10/EDA061 HT2015, Ulf Asklund 9
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
statusArea
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
Editor - JTextFieldJTextField används för textinmatning.
public class Editor extends JTextField implements ActionListener{
public Editor() { setBackground(Color.WHITE); addActionListener(this);
} public void actionPerformed(ActionEvent event) {
// activated by Return key// contents returnedby getText()
} }
EDAF10/EDA061 HT2015, Ulf Asklund 10
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
WindowMenu
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
WindowMenuItemclass WindowMenuItem extends JMenuItem
implementsActionListener { private Gui gui; public WindowMenuItem(Gui gui) {
super(gui.getTitle()); this.gui = gui; addActionListener(this);
} public void actionPerformed(ActionEvent event) {
gui.toFront(); }
}
EDAF10/EDA061 HT2015, Ulf Asklund 11
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
JMenupublic class WindowMenu extends JMenuimplements Observer {
private GuiList guiList; public WindowMenu(GuiList guiList) {
super("Window"); this.guiList = guiList; guiList.addObserver(this); update(null, null);
} public void update(Observable observable, Object object) {
removeAll(); for (Gui gui : guiList) {
add(new WindowMenuItem(gui)); }
} }
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
GuiListpublic class GuiList extends Observable
implementsIterable<Gui> { private List<Gui> list = new ArrayList<Gui>(); public void add(Gui gui) {
list.add(gui); setChanged(); notifyObservers();
} public Iterator<Gui> iterator() {
return list.iterator(); } //omissions
}
EDAF10/EDA061 HT2015, Ulf Asklund 12
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
MouseListenerNågra swing-komponenter kan ha en ActionListener, t ex: JButton, JMenuItem, JTextField.
Alla komponenter kan ha en MouseListener. Den läggs till medpublic void addMouseListener(MouseListener listener);
public interface MouseListener { void mouseClicked(MouseEvent event); void mouseEntered(MouseEventevent); void mouseExited(MouseEvent event); void mousePressed(MouseEvent event); void mouseReleased(MouseEvent event);
}
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
MouseAdapterI regel vill man bara reagera på en av händelserna. Då är det bekvämt med public abstract class MouseAdapter {
public void mouseClicked(MouseEvent event){} public void mouseEntered(MouseEvent event){} public void mouseExited(MouseEvent event){} public void mousePressed(MouseEvent event){} public void mouseReleased(MouseEvent event){}
}
EDAF10/EDA061 HT2015, Ulf Asklund 13
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
MouseListenerLabelpublic class MouseListenerLabel extends JLabel {
private class ClickListenerextends MouseAdapter { public void mouseClicked(MouseEvent event) {
setBackground(Color.YELLOW); }
} public MouseListenerLabel() {
setBackground(Color.WHITE); addMouseListener(newClickListener());
} }
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
Felhantering
EDAF10/EDA061 HT2015, Ulf Asklund 14
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
Felhantering, forts.public class XLException extendsRuntimeException {
private Object object;public XLException(String message, Object object) {
super(message); this.object = object;
} public Object getObject() {
return object; }
}
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
Feldetekteringpublic class Div extends BinExpr {
public Div(Exprexpr1, Expr expr2) {super(expr1, expr2);
} protected double op(double op1, double op2) {
if (op2 != 0) return op1 / op2;
elsethrow new XLException(”division by zero”, this);
} }
EDAF10/EDA061 HT2015, Ulf Asklund 15
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
Felhantering…try {
value = expr.value(); } catch (XLException e) {
report(e.getMessage(), e.getObject()); }…
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
Model/View/Control
EDAF10/EDA061 HT2015, Ulf Asklund 16
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
Model/View/Control-arkitektur• Modellen beskriver systemets tillstånd.
• Vyn visar upp systemets tillstånd.
• Control förändrar systemets tillstånd.
View ControlModel
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
Model/View/Control-implementering
Paketberoenden
View ControlModel
JFrame JButton
View
<<interface>>ActionListener
View Model Control
EDAF10/EDA061 HT2015, Ulf Asklund 17
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
Model/View/ControlVarför?
• Principen om enkelt ansvar.
• Integritet: Modellen behöver inte känna till vyn.
• Flera vyer av en modell.
Om Control saknar tillstånd slår vi ofta ihop vyn och control till ett grafiskt användargränssnitt, GUI.
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
Observer• Observer-mönstret används för att separera ”modellen” från
användargränssnittet, ”vyn”.
• Vyn implementerar gränssnittet Observer.
• Modellen utvidgar klassen Observable.
• När modellens tillstånd förändras informeras alla observatörer om att det skett en förändring och vyerna uppdaterar sig genom att hämta information från modellen.
• Observer/Observable är ett ramverk; klasserna finns färdiga.
EDAF10/EDA061 HT2015, Ulf Asklund 18
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
Observer & ObservableFinns i java.util
public class Observable {public void addObserver(Observer observer) public void deleteObserver(Observer observer) protected voidsetChanged()public void notifyObservers(Object object) public void notifyObservers()// omissions
}
public interface Observer {public void update(Observable observable, Object object);
}
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
Observer-mönstret
Metoden state() i modellen är en sorts getter. Det är bra om denna inte avslöjar hur tillståndet representeras.
EDAF10/EDA061 HT2015, Ulf Asklund 19
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
Observer-mönstret
Metoden state() i modellen är en sorts getter. Det är bra om denna inte avslöjar hur tillståndet representeras.
public class Model extends Observable { private int state;public void changeState() {
state++; setChanged(); notifyObservers();
}public String state() {
return String.valueOf(state); }
}
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
Observer-mönstret
Metoden state() i modellen är en sorts getter. Det är bra om denna inte avslöjar hur tillståndet representeras.
public class View extends JLabel implements Observer { private Model model;
public View(Model model) { this.model = model; model.addObserver(this);
}
public void update(Observable observable, Object object) { setText(model.state());
} }
Tydlig koppling till modellen.
EDAF10/EDA061 HT2015, Ulf Asklund 20
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
Observer-mönstret
Metoden state() i modellen är en sorts getter. Det är bra om denna inte avslöjar hur tillståndet representeras.
public class View extends JLabel implements Observer {
public View(Model model) { model.addObserver(this);
}
public void update(Observable observable, Object object) { Model model = (Model) observable; setText(model.state());
} }
Mindre tydlig koppling till modellen.
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
Ihopkoppling av vy och modellSkapa model och vy enligt exemplet ovan:
Model model = new Model(); View view = new View(model);
Kopplingen mellan vy och modell kan också göras där vy och modell skapas:
Model model = new Model(); View view = new View(); model.addObserver(view);
Någon nackdel?
EDAF10/EDA061 HT2015, Ulf Asklund 21
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
Java.util.Observable implementering…public class Observable {
private boolean changed = false;private Vector<Observer> vector = new Vector<Observer>();public synchronized voidaddObserver(Observer observer) {
if (!vector.contains(observer)) { vector.add(observer);
} } protected synchronizedvoid setChanged() {
changed = true; } ...
}
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
… java.util.ObservableNågot förenklad: public class Observable {
private boolean changed = false;private Vector<Observer> vector = new Vector<Observer>();public void notifyObservers() {
notifyObservers(null); } public synchronized voidnotifyObservers(Object arg) {
if (!changed) { return;
} changed = false;for (Observer observer: vector) {
observer.update(this, arg); }
} }
EDAF10/EDA061 HT2015, Ulf Asklund 22
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
MVC med Observer• En eller flera vyer registrerar sig som observatörer av
modellen via addObserver. OCP – Open-Closed Principle
• Ett kommando modifierar modellens tillstånd.
• Modellen informerar Observable att tillståndet förändrats via setChanged.
• Modellen begär att observatörerna informeras genom notifyObservers.
• notifyObservers i Observable informerar observatörerna via update om att modellen förändrats.
• Observatörerna hämtar modellens nya tillstånd och uppdaterar vyerna.
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
Sekvensdiagram• Anrop av en metod i modellen som ändrar dess tillstånd så
att vyerna ska uppdateras.
EDAF10/EDA061 HT2015, Ulf Asklund 23
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
Observer, update-parametrarnapublic interface Observer {
public void update(Observable observable, Object object); }
När man anropar notifyObservers(object) i modellen kommer update(Observable, Object) att anropas i alla observatörer.
Vad skall man använda argumenten till?
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
Update(observable, …)Observable kan användas för att komma åt modellen.
• Det är tydligare att ge observatören tillgång till modellen via observatörens konstruerare.
EDAF10/EDA061 HT2015, Ulf Asklund 24
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
Update(…, object)Object kan användas för att skicka information från modellen till vyn.
Fråga: Hur kan modellen veta vad vyn vill ha?
Svar: Det kan den inte veta.
Fråga: Det kan finnas flera observatörer som vill veta olika saker. Hur skall informationen förpackas?
Svar: Det är svårt att veta om man inte känner till alla observatörer som kan vara aktuella. Det finns ingen naturlig plats att dokumentera förpackningen.
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
Designprincip för Observer.update
Undvik att använda parametrarna.
EDAF10/EDA061 HT2015, Ulf Asklund 25
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
ExempelAritmetiska uttryck
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
Aritmetiska uttryck – Konkret syntax• Ett uttryck består av en eller flera termer separerade av enkla
plus- eller minus-tecken.
• En term består i sin tur av en eller flera faktorer separerade av enkla multiplikations- eller divisionstecken.
• En faktor är ett tal, en variabel eller ett uttryck inom parenteser.
• Ett tal består av en eller flera siffror och får inledas med ett minustecken.
• En variabel består av en eller flera bokstäver bland a–z.
EDAF10/EDA061 HT2015, Ulf Asklund 26
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
Konkret grammatik - BNFExpr ::= term (addop term)∗Term ::= factor (mulop factor)∗Factor::= number | name | ’(’ expr ’)’ Addop::= ’+’ | ’−’Mulop::= ’∗’ | ’/’
number ::= unsignedNumber | ’−’ unsignedNumberunsignedNumber ::= digit (digit)∗digit ::= ’0’ | ’1’ | ’2’ | ’3’ | ’4’ | ’5’ | ’6’ | ’7’ | ’8’ | ’9’ name ::= letter (letter)∗letter ::= ’a’ | ’b’ | ... | ’z’
Operatorer* upprepa 0 eller flera gånger | eller’ ’ literalt
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
Abstrakt representation – abstrakt grammatik
EDAF10/EDA061 HT2015, Ulf Asklund 27
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
Factory MethodSomeApp
Square
<<interface>>Shape
<<interface>>Shape Factory
+ make(String):Shape
Circle
<<creates>>
ShapeFactoryImplementation
Vad måste nu SomeApp känna till?
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
Java.io.StreamTokenizerpublic class StreamTokenizer {
public doublenval;public String sval;public int ttype = −4; public static final intTT EOF = −1, TT EOL = 10, TT NUMBER = −2, TT WORD = −
public StreamTokenizer(Reader r)public int nextToken() throws IOExceptionpublic void ordinaryChar(intch)\\ omissions
}
EDAF10/EDA061 HT2015, Ulf Asklund 28
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
Java.io.StreamTokenizerpublic class ExprParser extends StreamTokenizer {
private int token;public ExprParser(String string) throws IOException {
super(new StringReader(string)); ordinaryChar(’−’); ordinaryChar(’/’);token = nextToken();
}
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
Analys av faktorerprivate Expr factor() {
Expr e; switch (token) {
case ’(’: token = nextToken(); e = expr(); token = nextToken(); return e;
case TT NUMBER: double x = nval; token = nextToken(); return new Num(x);
case TT WORD: String s = sval; token = nextToken(); return new Variable(s);
}}
EDAF10/EDA061 HT2015, Ulf Asklund 29
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund
Analys av termerprivate Expr term() {
Expr result, factor;result = factor();while (token == ’∗’ || token == ’/’) {
int op = token; token = nextToken(); factor = factor(); switch (op) {case ’∗’ :
result = new Mul(result, factor); break; case ’/’ :
result = new Div(result, factor); break; }
} return result;
}
Datavetenskap/LTH | EDAF10/EDA061 HT2015 | Ulf Asklund