Software Engineering I (02161) Model-View-Controller Assoc. Prof. Hubert Baumeister DTU Compute Technical University of Denmark Spring 2020
Layered Architecture Important: ◮ No business logic in presentation layer or infrastructure/database layer ◮ No UI/GUI code in the application–/domain layer Eric Evans, Domain Driven Design, Addison-Wesley, 2004
Example Vending Machine Two different presentation layers; same application layer ◮ Command line interface ◮ Swing GUI Current Money: DKK 5 0) Exit 1) Input 1 DKK 2) Input 2 DKK 3) Input 5 DKK 4) Select banana 5) Select apple 6) Cancel Select a number (0-6): 5 Rest: DKK 2 Current Money: DKK 0 Dispensing: Apple
Model View Controller (MVC) Invented by Trygve Reenskaug for Smalltalk-76/80 ◮ View : model state to display graphics View Controller ◮ Controller : mouse access view state paint processEvent and keyboard update events to messages Presentation Layer to model ◮ Model : Business Application/Domain Layer messages to model observer pattern logic access model state Model
MVC with Observer Pattern c:Controller m:Model v:View User handleEvent() doSomething() propertyChange(..) display() getState() doSomething() propertyChange(..) display() getState()
MVC Example: Drawing Program
JPanel «interface» «anonymous» PropertyChangeListener MouseAdapter mousePressed(e: MouseEvent) DrawingPanel DrawingApp propertyChange «anonymous» paint(g: Graphics) main MouseMotionAdapter mouseDragged(e: MouseEvent) * Presentation Layer Application Layer PropertyChangeSupport Drawing Polyline Point x: int model addPoint(p: Point) getXValues: int[*] y: int newLine getYValues: int[*] * * draw(g: Graphics) getSize: int draw(g: Graphics)
MVC Example: Drawing Program public class DrawingPanel extends JPanel implements PropertyChangeListener { Drawing model; public DrawingPanel(Drawing model) { this.model = model; model.addObserver(this); addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent e) { drawing.newLine(); } }); addMouseMotionListener(new MouseMotionAdapter() { public void mouseDragged(MouseEvent e) { drawing.addPoint(new Point(e.getX(),e.getY())); } }); } public void paint(Graphics g) { drawing.draw(g); } public void propertyChange(PropertyChangeEvent evt) { repaint(); } }
Drawing class public class Drawing { private PropertyChangeSupport support = new PropertyChangeSupport(this); private List<Polyline> lines = new ArrayList<>(); public void newLine() { lines.add(new Polyline()); support.firePropertyChange("drawing", null, null); } public void addPoint(Point p) { lines.get(lines.size() - 1).add(p); support.firePropertyChange("drawing", null, null); } ... }
Java and Swing «interface» PropertyChangeListener * Application JComponent «interface» main paint(g:Graphics) * * EventHandler propertyChange(...) processEvent(e:Event) «anonymous» ActionListener JButton JLabel JTextField JFrame JPanel performAction(e: ActionEvent) Presentation Layer Application/Domain Layer PropertyChangeSupport model ApplicatonFacade
Example Vending Machine Two different presentation layers; same application layer ◮ Command line interface ◮ Swing GUI Current Money: DKK 5 0) Exit 1) Input 1 DKK 2) Input 2 DKK 3) Input 5 DKK 4) Select banana 5) Select apple 6) Cancel Select a number (0-6): 5 Rest: DKK 2 Current Money: DKK 0 Dispensing: Apple
Architecture Presentation Layer Presentation Layer VendingMachineUI VendingMachineTextUI Application Layer VendingMachine <<enumeration>> Fruit dispensedItem: Fruit {readOnly} currentMoney: int {readOnly} APPLE totalMoney: int {readOnly} BANANA restMoney: int {readOnly} * input(money: int) select(f: fruit) cancel() VendingMachine acts as the facade (Facade Design Pattern)
Presentation Layer: Swing GUI public class VendingMachineUI extends implements PropertyChangeListener { private VendingMachine vendingMachine = new VendingMachine(10, 10); ... private JFrame topWindow = new JFrame(); private JButton fiveCrowns = new JButton(); private JTextField currentM = new JTextField(); ... private void initComponents() { fiveCrowns.setText("DKK 5"); fiveCrowns.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { fiveCrownsActionPerformed(evt); } } ) ... }; private void fiveCrownsActionPerformed(java.awt.event.ActionEvent evt) { vendingMachine.input(5); } ... public void propertyChange(PropertyChangeEvent evt) { currentM.setText("" + vendingMachine.getCurrentMoney()); ... } }
VendingMachineTextUI class public void mainLoop(InputStream in, PrintStream out) throws IOException { ... do { showMenu(out); choice = Integer.valueOf(in.readLine()); ... } processChoice(number, out); } while (true); } private void showMenu(PrintStream out) { ... out.println(" 3) Input 5 DKK"); .... out.println("Select a number (0-6): "); } private void processChoice(int number, PrintStream out) { switch (number) { ... case 3: vendingMachine.input(5); break; ... } }
VendingMachineTextUI class (cont.) public void propertyChange(PropertyChangeEvent evt) { String type = evt.getPropertyName(); switch (type) { ... case NotificationType.CURRENT_MONEY: System.out.println("Current Money: DKK " + vendingMachine.getCurrentMoney()); break; ... } }
Advantages of using MVC and separation of layers 1 Presentation layer easily changed 2 Additional presentation layers can be added easily without having to reimplement the business logic 3 Automatic tests: test the application and domain layer: test ”under the GUI”
Recommend
More recommend