Cop
yrig
ht ©
Pet
er B
unus
200
8 Peter Bunus Department of Computer and Information Science Linköping University, Sweden [email protected]
TDDB84 Design Patterns Lecture 07
Memento, Model-View-Controller
Command
TDDB84 Design Patterns Slide 2
Memento
TDDB84 Design Patterns Slide 3
The Memento – Non Software Example
! This pattern is common among do-it-yourself mechanics repairing drum brakes on their cars. The drums are removed from both sides, exposing both the right and left brakes .
! Only one side is disassembled, and the other side serves as a Memento of how the brake parts fit together
! Only after the job has been completed on one side is the other side disassembled. When the second side is disassembled, the first side acts as the Memento
The Memento captures and externalizes an object's internal state, so the object can be restored to that state later.
TDDB84 Design Patterns Slide 4
Memento
Originator o = new Originator(); o.state = "On"; // Store internal state Caretaker c = new Caretaker(); c.memento = o.CreateMemento(); // Continue changing originator o.State = "Off"; // Restore saved state o.SetMemento( c.Memento );
TDDB84 Design Patterns Slide 6
Memento – Another Non Software Example
Originator
Caretaker
34-55-09
Memento
TDDB84 Design Patterns Slide 8
Memento Example
+setMemento(in m : Memento)+createMemento()
-stateOriginator
+getState()+setState()
-stateMemento Caretaker
1
-memento
return new Memento(state)
state = m->getState
+writeCombination(in m : SafetyDeposit)+depositCombination()
-stateOwner
+getCombination()+setCombination()
-stateSafetyDeposit SecurityGuard
1
-safetyDeposit
return new SafetyDeposit(state)
state = m->getCombination()
TDDB84 Design Patterns Slide 9
Owner o = new Owner(); o.state = “123-45-78-45"; // Store code SecurityGuard c = new SecurityGuard(); c.safetyDeposit = o.depositCombination(); // Continue changing code o.state = “4444444444"; // Restore saved code o.writeCombination( c.SafetyDeposit );
Memento Example
+writeCombination(in m : SafetyDeposit)+depositCombination()
-stateOwner
+getCombination()+setCombination()
-stateSafetyDeposit SecurityGuard
1
-safetyDeposit
return new SafetyDeposit(state)
state = m->getCombination()
TDDB84 Design Patterns Slide 10
Memento – Rules of Thumb
Rules of thumb If you only need one Memento, combine the Originator and Caretaker into one object (Brown, 1998). If you need many Mementos, store only incremental changes (Brown, 1998) . This will help to save space. Memento often used in conjunction with Command, Iterator and Singleton. Implementation of the Memento design pattern varies depending on the programming language. Implement the Originator as a friend class to the Memento in C++. Implement the Memento as an inner-class of the Originator in Java (Achtziger, 1999) .
TDDB84 Design Patterns Slide 11
A Java Implementation of Memento
public class Originator { private T state; private class Memento { // value object private T mstate; private Memento(T state) { mstate = copy_of(state); } private T getState() { return mstate; } } public Memento createMemento() { return new Memento(state); } // continued...
TDDB84 Design Patterns Slide 12
A C++ Implementation of Memento
class Originator { public: Memento* CreateMemento(); void SetMemento(const Memento*); private: State* _state; // internal data structures
}; class Memento { public: virtual ~Memento(); private:
// private members accessible only to Originator friend class Originator; Memento(); void SetState(State*); State* GetState();
// ... private: State* _state; // ... };
n Only talk to your friends
TDDB84 Design Patterns Slide 13
The Constitution of Software Architects
! Encapsulate what varies
! Program through an interface not to an implementation
! Favor Composition over Inheritance
! Classes should be open for extension but closed for modification
! Don’t call us, we’ll call you
! A Class should have only one reason to change
! Depend upon abstractions. Do not depend upon concrete classes.
! Strive for loosely coupled designs between objects that interact
! Only talk to your friends
TDDB84 Design Patterns Slide 14
Memento Advantages and Disadvantages
! Since OO programming dictates that objects should encapsulate their state it would violate this law if objects’ internal variables were accessible to external objects. The memento pattern provides a way of recording the internal state of an object in a separate object without violating this law
! It eliminates the need for multiple creation of the same object (i.e. Originator) for the sole purpose of saving its state. Since a scaled down version of the Originator is saved instead of the full Originator object, space is saved.
! It simplifies the Originator since the responsibility of managing Memento storage is no longer centralized at the Originator but rather distributed among the Caretakers.
! The Memento object must provide two types of interfaces: a narrow interface to the Caretaker and a wide interface to the Originator. That is, it must acts like a black box to everything except for the class that created it
! Using Mementos might be expensive if the Originator must store a large portion of its state information in the Memento or if the Caretakers constantly request and return the Mementos to the Originator. Therefore, this pattern should only be used if the benefit of using the pattern is greater than the cost of encapsulation and restoration
TDDB84 Design Patterns Slide 15
Programming Styles
! Normal (control flow-based) programming • Approach
– Start at main() – Continue until end of program or exit()
! Event-driven programming • Unable to predict time & occurrence of event • Approach
– Start with main() – Build GUI – Await events (& perform associated computation)
TDDB84 Design Patterns Slide 16
Model-View-Controller (MVC) Pattern
! Developed at Xerox PARC in 1978 ! Separates GUI into 3 components
• Model ⇒ application data • View ⇒ visual interface • Controller ⇒ user interaction
Model
View
Controller
TDDB84 Design Patterns Slide 17
MVC Interaction Order
1 User performs action, controller is notified 2 Controller may request changes to model 3 Controller may tell view to update 4 Model may notify view if it has been modified 5 View may need to query model for current data 6 View updates display for user
Model
View
Controller 1
2
3
4,5 6
TDDB84 Design Patterns Slide 18
MVC Pattern – Controller
! Users interact with the controller ! Interprets mouse movement, keystrokes, etc. ! Communicates those activities to the model ! Interaction with model indirectly causes view(s) to update
Controller Obesity
TDDB84 Design Patterns Slide 19
TDDB84 Design Patterns Slide 20
MVC Pattern – Model
! Contains application & its data ! Provide methods to access & update data ! Interface defines allowed interactions ! Fixed interface enable both model & GUIs to be easily pulled
out and replaced ! Examples
• Text documents • Spreadsheets • Web browser • Video games
TDDB84 Design Patterns Slide 21
MVC Pattern – View
! Provides visual representation of model ! Multiple views can display model at same time
• Example: data represented as table and graph ! When model is updated, all its views are informed & given
chance to update themselves
Keeping the View Simple
TDDB84 Design Patterns Slide 22
TDDB84 Design Patterns Slide 23
The User View of the MVC
TDDB84 Design Patterns Slide 24
MVC as a Compound Design Pattern
TDDB84 Design Patterns Slide 25
MVC Song
TDDB84 Design Patterns Slide 26
TDDB84 Design Patterns Slide 27
Command – Non Software Example
TDDB84 Design Patterns Slide 28
Running the Restaurant
I’ll have a Cheese Pizza with a capuccino
Order
Cheese Pizza
Capuccino
Order Cheese Pizza Capuccino
createOrder()
takeOrder()
orderUp()
makePizza() prepareCoffee()
output
TDDB84 Design Patterns Slide 29
From Lunch to Command Pattern
Client Command
setCommand()
Invoker
Receiver
The client is responsible for creating the command object. The command object consist of a set of actions and a receiver
createCommandObject()
The command object provides one method execute(), that encapsulates the actions and can be called to invoke the actions on the Receiver
The client calls setCommand on an Invoker object and passes it the command object, where if gets stored until it is needed
setCommand()
execute()
Command
execute()
At some points in the future the Invoker() calls the command object’s execute() method
execute()
action1() action2()
Which result in the actions being invoked on the Receiver
TDDB84 Design Patterns Slide 30
The Ultimate Remote Control
Joe’s Ultimate Remote Control
On Off
On Off
On Off
On Off
On Off
On Off
On Off
Undo
TDDB84 Design Patterns Slide 31
+high()+medium()+low()+off()+getSpeed()
CeilingFan
+on()+off()+setInputChanel()+setVolume()
TV
+on()+off()+dim()()
CeilingLight
+circulate()+jetsOn()+jetsOff()+setTemperature()
Hottub
Different Interfaces
+on()+off()
DeskLamp
TDDB84 Design Patterns Slide 32
The Command Interface
+on()+off()
Light public interface Command { public void execute();
}
public class LightOnCommand implements Command { Light light; public LightOnCommand(Light light) { this.light = light; } public void execute() { light.on(); } }
TDDB84 Design Patterns Slide 33
Using the Command Object
// // This is the invoker // public class SimpleRemoteControl { Command slot;
public SimpleRemoteControl() {}
public void setCommand(Command command) { slot = command; }
public void buttonWasPressed() { slot.execute(); }
}
TDDB84 Design Patterns Slide 34
Testing the Remote Control
public class RemoteControlTest { public static void main(String[] args) { SimpleRemoteControl remote = new SimpleRemoteControl(); //Invoker Light light = new Light(); //Receiver LightOnCommand lightOn = new LightOnCommand(light); //Command remote.setCommand(lightOn); remote.buttonWasPressed();
} }
The Client is responsible of creating a ConcreteCommand and setting its receiver
The receiver knows how to perform the work needed to carry out the request
The Invoker holds a command and at some point ask the command to carry out a request by calling its execute() method
The execute method invokes the action(s) on the receiver needed to fulfilll the request
TDDB84 Design Patterns Slide 35
More Concrete Commands
public class GarageDoorOpenCommand implements Command { GarageDoor garageDoor;
public GarageDoorOpenCommand(GarageDoor garageDoor) {
this.garageDoor = garageDoor;
}
public void execute() {
garageDoor.up();
}
} public class RemoteControlTest { public static void main(String[] args) { SimpleRemoteControl remote = new SimpleRemoteControl(); Light light = new Light(); GarageDoor garageDoor = new GarageDoor(); LightOnCommand lightOn = new LightOnCommand(light); GarageDoorOpenCommand garageOpen =
new GarageDoorOpenCommand(garageDoor); remote.setCommand(lightOn); remote.buttonWasPressed(); remote.setCommand(garageOpen); remote.buttonWasPressed(); } }
TDDB84 Design Patterns Slide 36
Assigning Commands to Slots
Joe’s Ultimate Remote Control
On Off
On Off
On Off
On Off
On Off
On Off
On Off
Undo
Living room light
Kitchen light
Ceiling Fan
Garage Door
Stereo
All Lights
Playstation
Each slot gets a command
LightOnCommand
execute()
LightOnCommand
execute()
CeilingFanHigh
execute()
GarageDoorOpen
execute()
PlaystationOn
execute()
LightOffCommand
execute()
LightOffCommand
execute()
CeilingFanOff
execute()
GarageDoorClose
execute()
PlaystationOff
execute()