1 1.Mediator 2.Observer 3.Chain of Responsibilitiy 4.Command 5.Strategy 6.Iterator 7.State...
-
Upload
blake-craze -
Category
Documents
-
view
217 -
download
0
Transcript of 1 1.Mediator 2.Observer 3.Chain of Responsibilitiy 4.Command 5.Strategy 6.Iterator 7.State...
1
1. Mediator2. Observer3. Chain of Responsibilitiy4. Command5. Strategy6. Iterator7. State8. Memento
2
Introduction
f
f
f
focused on - typical communication between objects- assignment of responsibilities between objects
Class patternsinheritance for distributing responsibilities
- Template method- Interpreter
Object patterns- target loose coupling between communicating objects
Mediator, Chain of Responsibility, Observer- encapsulate behavior in object
Strategy, Command, State, Visitor, Iterator
3
MotivationInteraction between many objectsDefault solution : objects contain references to each other
Worst case : for N objects -> N*(N-1) referencesProblem : difficult to reuse object/class
A
B
C
DE
4
SolutionColleagues (A,B,C,D,E)
Interacting objectsONLY refer to single object “Mediator”
Mediator (M)Knows all interacting objectsSingle point of contactManages interaction
A
B
C
DE
M
5
Example : Hotel cleaning
Hotel has- number of Rooms- number of Housekeepers
Each Housekeeper is responsible for number of Rooms(Many-to-many)
State of Room-available ?-clean ?
7
No Mediator [Hotel]class Hotel { private String name="HotelName"; private Room[] r; private Housekeeper[] h; public Hotel(String n,Room[] rr,Housekeeper[] hh) {name=n;r=rr;h=hh;} public String toString() {return "Hotel : "+name+" ";} public Room searchRoom() { for(Room ri : r) if(ri.isAvailable()&&ri.isCleaned()) return ri; for(Housekeeper hi : h) for(Room ri:r) if(ri.isAvailable()&&hi.cleanRequest(ri))
return ri; return new Room("0.0"); // no room available ! }}
8
No Mediator [Housekeeper]class Housekeeper { private String name="HousekeeperName"; private ArrayList toClean=new ArrayList(); public Housekeeper(String n) {name=n;} public void setRoomsToClean(Room[] r) {
for(Room ri:r) {toClean.add(ri);ri.addHousekeeper(this);}} public String toString() { String r= "Housekeeper : "+name; return r; } public boolean cleanRequest(Room r) { if(toClean.contains(r)) { r.clean(this); System.out.println(this+" cleaned "+r); return true; } else { System.out.println(this+" refused cleaning "+r);return false; } } }
9
No Mediator [Room]class Room { private String number; private boolean available=true; private boolean cleaned=true; private ArrayList hk=new ArrayList(); public void addHousekeeper(Housekeeper h) {hk.add(h);} public void removeHousekeeper(Housekeeper h) {hk.remove(h);} public Room(String n) {number=n;} public String toString() {return
"["+number+" available :"+available+" cleaned : "+cleaned+"]";} public void book() {available=false;} public void unbook() {available=true;cleaned=false;} public void clean(Housekeeper h) { if(hk.contains(h)) {cleaned=true;} else {System.out.println("Access error : "+this);} } public boolean isCleaned() {return cleaned;} public boolean isAvailable() {return available;}}
10
No Mediator [Test]public class NoMediator { public static void main(String[] args) { Room[] r={new Room("1.1"),new Room("1.2"),new Room("1.3"),
new Room("2.1"),new Room("2.2"),new Room("2.3")}; Housekeeper[] h={new Housekeeper("An"),new Housekeeper("Bert"),
new Housekeeper("Cecilia"),new Housekeeper("Dave")}; Hotel fancy=new Hotel("Fancy Hotel",r,h); h[0].setRoomsToClean(new Room[] {r[0],r[1],r[2]}); h[1].setRoomsToClean(new Room[] {r[3],r[4],r[5]}); h[2].setRoomsToClean(new Room[] {r[0],r[3],r[1],r[4]}); h[3].setRoomsToClean(new Room[] {r[1],r[2],r[4],r[5]}); for(int i=0;i<5;i++) r[i].book(); for(int i=0;i<5;i+=2) r[i].unbook(); for(int i=0;i<5;i++) { Room room=fancy.searchRoom(); System.out.println("--> "+i+" "+room); room.book(); } } }
12
Mediated Hotel [Mediator]class Mediator { private Housekeeper[] h; private Room[] r; private Map<Housekeeper,ArrayList<Room>> m
=new HashMap<Housekeeper,ArrayList<Room>>(); public void setRoomsToClean(Housekeeper hi,Room[] ri) { ArrayList<Room> r=new ArrayList<Room>(); for(Room room:ri) r.add(room); m.put(hi,r); } public Mediator(Room[] ri,Housekeeper[] hi) { r=ri;h=hi; for(Room room:r) room.setMediator(this); for(Housekeeper hk:h) hk.setMediator(this); } // ...}
13
Mediated Hotel [Mediator]class Mediator { //... public void changed(Colleague c) { for(Housekeeper hi:h) { if(hi.equals(c)) {System.out.println(this+" is cleaning ...");} } for(Room ri:r) { if(ri.equals(c)) { System.out.println(" "+(Room)c+" was cleaned."); } } } public boolean cleanRequest(Housekeeper h,Room r) { ArrayList<Room> toClean=m.get(h); if(toClean.contains(r)) {r.clean();return true; } else { System.out.println(h+" refused cleaning "+r);return false; } }}
14
Mediated Hotel [Colleague,Room]
class Colleague { protected Mediator director; public void setMediator(Mediator m) {director=m;} public void changed(){director.changed(this);}}class Room extends Colleague { private String number; private boolean available=true,cleaned=true; public Room(String n) {number=n;} public String toString() {return "["+number+"]";} public void book() {available=false;} public void unbook() {available=true;cleaned=false;} public void clean() { // anything to clean the room cleaned=true; changed(); } public boolean isCleaned() {return cleaned;} public boolean isAvailable() {return available;}}
15
Mediated Hotel [Housekeeper]
class Housekeeper extends Colleague { private String name="HousekeeperName"; public Housekeeper(String n) {name=n;} public String toString() { String r= "Housekeeper : "+name; return r; } public void cleanRequest() { // anything to clean ... changed(); } }
16
Mediated Hotel [Hotel]
class Hotel extends Colleague { private String name="HotelName"; private Room[] r; private Housekeeper[] h; public Hotel(String n,Room[] rr,Housekeeper[] hh) {name=n;r=rr;h=hh;} public String toString() {return "Hotel : "+name+" ";} public Room searchRoom() { for(Room ri : r) if(ri.isAvailable()&&ri.isCleaned()) return ri; for(Housekeeper hi : h) for(Room ri:r)
if(ri.isAvailable()&&director.cleanRequest(hi,ri) ) return ri;
return new Room("0.0"); // no room available ! }}
17
Mediated Hotel [Test]public class WithMediator { public static void main(String[] args) { Room[] r={new Room("1.1"),new Room("1.2"),new Room("1.3"),
new Room("2.1"),new Room("2.2"),new Room("2.3")}; Housekeeper[] h={new Housekeeper("An"),new Housekeeper("Bert"),
new Housekeeper("Cecilia"),new Housekeeper("Dave")}; Hotel fancy=new Hotel("Fancy Hotel",r,h);Mediator m=new Mediator(r,h); m.setRoomsToClean(h[0],new Room[] {r[0],r[1],r[2]}); m.setRoomsToClean(h[1],new Room[] {r[3],r[4],r[5]}); m.setRoomsToClean(h[2],new Room[] {r[0],r[3],r[1],r[4]}); m.setRoomsToClean(h[3],new Room[] {r[1],r[2],r[4],r[5]}); fancy.setMediator(m); for(int i=0;i<5;i++) r[i].book(); for(int i=0;i<5;i+=2) r[i].unbook(); for(int i=0;i<5;i++) { Room room=fancy.searchRoom(); System.out.println("--> "+i+" "+room);room.book(); } }}
18
General Solution
Mediator : defines interface to communicate with ColleaguesConcreteMediator :
- coordinates Colleague objects- knows and manages Colleague collection
Colleague :- knows Mediator object- communicates through Mediator with Colleagues
19
Consequences
1. limits subclassing• changing behaviour : subclass Mediator instead of all
Colleagues2. Decouples Colleagues3. Simplifies object protocols
• replaces many-to-many by one-to-many4. Interaction between Colleagues in one class only
(separates behavior associated with collaboration and ownbehavior)
5. Centralizes control• Mediator can become complex
20
Implementation
Abstract Mediator class- allows Colleagues to engage in multiple cooperations- can be avoided (see Hotel example) in case of 1 cooperation only
Communication Mediator – ColleaguesMediator should be notified of important events
- use Observer pattern - Mediator = Observer- Colleague = Subject- Mediator reacts upon events from Colleagues
- Special notification (see Hotel example)
21
Motivation
Organise efficiently one-to-many relations between objects
A
B
C
D
- propagate state changes of A to B, C and D
- dynamically manage collection of objects to notify
- objects to notify not known in advance
heavily used in- MVC based systems- event based systems (publish-subscribe)- Mediator-Colleague communication
23
Hotel cleaning
class Hotel { // as before public void notifyCleaned(Room r) { System.out.println("Hotel "+this+" room "+r+" cleaned."); }}class Housekeeper { // as before public void notifyCleaned(Room r) { System.out.println(this+" received message cleaning room "+r); } }
24
Hotel cleaningclass Room { // as before private Hotel h; private ArrayList<Housekeeper> hk=new ArrayList(); public void setHotel(Hotel hi) {h=hi;} public void addHousekeeper(Housekeeper h) {hk.add(h);} public void removeHousekeeper(Housekeeper h) {hk.remove(h);} public void clean(Housekeeper h) { if(hk.contains(h)) { cleaned=true; for(Housekeeper hh:hk) hh.notifyCleaned(this); h.notifyCleaned(this); } else { System.out.println("Access error to clean room "+this); } }}// test code as before (see code for no mediator)
26
Observed hotel cleaningclass Subject { private ArrayList<Observer> l=new ArrayList<Observer>(); public void add(Observer o) {l.add(o);} public void remove(Observer o) {if(l.contains(o)) l.remove(o);} public void notifyObservers() {for(Observer o:l) o.update(this);}} interface Observer { void update(Subject s);} class Hotel implements Observer { // as before ... public void update(Subject s) { System.out.println("Hotel "+this+" room "+s+" cleaned."); }}
27
Observed hotel cleaningclass Housekeeper implements Observer { // as before ... public void update(Subject s) { System.out.println(this+" received message cleaning room "+s); } }class Room extends Subject { // as before, NO Hotel aggregate object public void clean(Housekeeper h) { if(hk.contains(h)) { cleaned=true; notifyObservers(); } else { System.out.println("Access error to clean room "+this); } }}// main test method as before
29
General solution
Subject- knows all Observers watching- provides interface for adding/removing Observers
Observer : defines update-interface for observing objectsConcreteSubject
- stores relevant state for ConcreteObservers- notifies when relevant state changes
ConcreteObserver- has reference to ConcreteSubject (possibly through update())- implements Observer interface, keeps state consistent
31
Consequences
1. Abstract coupling of Subject and Observers• reuse of Subject/Observer code• Can belong to different parts of the system to build
2. Facilitates broadcasts• message destinations can be specified at runtime
3. Unexpected updatesSubject does not know effect of sending update message
• cascade of updates• standard patterns does not indicate WHAT is changed
32
Implementation issues
1. Many Subjects, few Observers-> store relation in HashMap
2. Observing more than 1 SubjectIdentify sending object (e.g. by passing this-reference in update)
3. Update responsibility1. Subject calls notify :
+ guarantee for consistency- low update granularity
2. Client calls notify- no guarantee for consistency (client might forget)+ more efficient through coarser granularity
4. Dangling references when Subject is deletedSubject should notify Observers prior to deletion
5. Subject state should be consistent PRIOR to notification !
33
Implementation issues6. Push – Pull ?
push : - Subject sends info on change to Observers- can introduce unwanted dependency / reduced reuse
pull :- Observer requests info from Subject after being notified- possibly inefficient
7. Update granularityenhance Subject interface to allow registration for specificstate updates (e.g. one field only, large changes only, etc.)
add(Observer o, Aspect a)update(Subject s, Aspect a)
8. Complex updatesin case of complex dependencies -> use ChangeManagere.g. organise updates in Directed Acyclic Graph to reduce updates
34
Chain of Responsibility
Motivation :Decouple Sender and Handler of requestSet of Handlers can fulfill requestSet is ordered in linked list
Client B C D
Usage :- if handler is not known beforehand- Client code abstract in terms of handler- chain should be configured dynamically
Handlers
35
General Solution
handleRequest : recursive call down the chainClient : initiates requestHandler :
- defines interface for request handling- knows how to find successor in chain (can be deferred to subclass)
ConcreteHandler :- handles request if responsible, or forwards otherwise- can access successor
36
ConsequencesImplementationConsequences1. Reduced coupling
• client does not know object that will eventually handle request• reduced inter-object links (easier to maintain)
2. Flexible distribution of responsibilitieschange the chain at runtime
3. No guarantee the request will be handled !
Implementation issues1. Defining the chain
new links (linked list is popular choice)existing links (e.g. containment hierarchy)
2. Request representationsimple hard coded requesttype of request encoded (int, String, ...)
-> handler decodes request type and decides
whether to handle or forward
37
Implementation Issues
1. Defining the chain1. new links (linked list is popular choice)2. existing links (e.g. containment hierarchy)
2. Request representation1. simple hard coded request2. type of request encoded (int, String, ...)
-> handler decodes request type and decides whether to handle or forward
38
MotivationMotivation :
- functor mechanism : function is first class object- decouple client from server and exact command to execute- provide facilities to
- queue requests- log requests- undo/redo requestsExample :
interface toolkit - commands will travel from UI to handling objects- content/meaning of command not known when toolkit developed
Usage :- to parametrize objects by an action to perform- time decoupling : specify – queue – execute request
(Command can live longer than requestor)- undo : Command can know how to undo itself.
40
Example : Hotelclass Hotel { private String name="HotelName"; private Room[] r; public Hotel(String n,Room[] rr) {name=n;r=rr;} public String toString() {
String s="";for(Room rr:r) s+=rr;return "Hotel : "+name+" "+s;
} public Room searchRoom() { for(Room ri : r) if(ri.isAvailable()) return ri; return new Room("0.0"); // no room available ! } public boolean bookRoom(Room rr) { boolean ok=rr.isAvailable(); if(ok) rr.book(); return ok; }}
41
Example : Room
class Room { private String number; private boolean available=true; public Room(String n) {number=n;} public String toString() {
return "["+number+" available :"+available+"]"; } public void book() {available=false;} public void unbook() {available=true;} public boolean isAvailable() {return available;}}
42
Example : Commands [1]interface Command { void execute();}
abstract class HotelCommand implements Command { protected Hotel h; protected Room r; public HotelCommand(Hotel hh,Room rr) {h=hh;r=rr;} abstract public void execute(); public Room getRoom() {return r;}}
class BookCommand extends HotelCommand { public BookCommand(Hotel hh,Room rr) {super(hh,rr);} public void execute() { h.bookRoom(r); }}
43
Example : Commands [2]class SearchCommand extends HotelCommand { public SearchCommand(Hotel hh) {super(hh,null);} public void execute() { r=h.searchRoom(); } }class SearchBookCommand extends HotelCommand { public SearchBookCommand(Hotel hh) {super(hh,null);} public void execute() { SearchCommand sc=new SearchCommand(h); sc.execute(); r=sc.getRoom(); BookCommand bc=new BookCommand(h,r); bc.execute(); }}
44
Example : TravelAgency
class TravelAgency { private ArrayList<Command> cl=new ArrayList<Command>(); public void addCommand(Command c) {cl.add(c);} public void execute() { for(Command c:cl) c.execute();// make list empty ? }}// could also be Command (composite)
45
Example : Test codepublic static void main(String[] args) { Room[] rfancy={new Room("1.1"),new Room("1.2"),new Room("1.3"),
new Room("2.1"),new Room("2.2"),new Room("2.3")}; Hotel fancy=new Hotel("Fancy Hotel",rfancy); Room[] rmayfair={new Room("A.1"),new Room("A.2"),new Room("A.3"),
new Room("B.1"),new Room("B.2"),new Room("B.3")}; Hotel mayfair=new Hotel("Mayfair Hotel", rmayfair); BookCommand bc=new BookCommand(fancy, rfancy[2]); TravelAgency tui=new TravelAgency(); tui.addCommand(bc); tui.execute(); // book room SearchBookCommand[] sc=new SearchBookCommand[8]; // search&book 8 rooms for(int i=0;i<sc.length;i++) { sc[i]=new SearchBookCommand(mayfair); tui.addCommand(sc[i]); } tui.execute(); for(SearchBookCommand s:sc) System.out.println(s.getRoom());}
46
General Solution
Command : provides interface to execute operationConcreteCommand :
- knows Receiver- execute : invoke action on receiver
Client :- create ConcreteCommands- set Receiver for Commands
Invoker : causes Commands to executeReceiver : implements logic of operation
48
ConsequencesImplementation
Consequences• Decoupling of invoker and logic implementation (functional and in time)• Commands are first class objects (“functors”)• Composite Commands can be constructed (Composite design pattern)• Easy to add new Commands
Implemention1. Commands intelligence
• just dispactching• does everything (no receiver)• finds receiver dynamically (at runtime)
2. Support for undo/redo3. Error accumulation in undoing
49
Undo/RedoUndoable Commands :
- extend interface with undo()- additional state :
- Receiver object- arguments used when invoking action on receiver- state of Receiver prior to invoking actionBUT : Receiver must support operations for restoring
prior stateApplication changes :
1 level of undo : just keep track of last Commandmany levels : keep history list of CommandsMake deep copy of Command ! (e.g. use Prototype design pattern)
Accumulating errors :problem : undo/redo not entirely inverse operationsSolution : make copy of prior state of more objects
(Use Memento design pattern)
50
Motivation
Allow to select algorithm at runtimeAlternative algorithms belong to same family
Usage :- configure classes/object with behavior
many alternative behaviorseach alternative is strategy
- different algorithmic flavours, specialized in dedicated situations- hide algorithm specific data from client objects
51
Example : Strategic Hotel
- searching Room : delegated to SearchStrategy- SearchStrategy has access to its data (the Rooms) through Hotel object (“Context”)
52
Example : Hotel + Roomclass Hotel { private String name="HotelName"; private Room[] r; private SearchStrategy s; public void setSearchStrategy(SearchStrategy ss){s=ss;s.setHotel(this);} public Room[] getRooms() {return r;} // context interface public Hotel(String n,Room[] rr) {name=n;r=rr;} public String toString() {String s="";for(Room rr:r) s+=rr;
return "Hotel : "+name+" "+s;} public Room searchRoom() {return s.searchRoom(); /* delegation ! */} public boolean bookRoom(Room rr) { boolean ok=rr.isAvailable(); if(ok) rr.book(); return ok; }}class Room { // as before}
53
Example : Strategiesabstract class SearchStrategy { protected Hotel h; public abstract Room searchRoom(); void setHotel(Hotel hh) {h=hh;}}class RandomSearchStrategy extends SearchStrategy { public Room searchRoom() { Room[] r=h.getRooms(); int i=(int)(Math.random()*r.length); return r[i]; }}class FirstAvailableStrategy extends SearchStrategy { public Room searchRoom() { Room[] r=h.getRooms(); for(Room ri:r) if(ri.isAvailable()) return ri; Room zero=new Room("0.0");zero.book();return zero; }}
54
Example : Test code public static void main(String[] args) { Room[] rfancy={new Room("1.1"),new Room("1.2"),new Room("1.3"),
new Room("2.1"),new Room("2.2"),new Room("2.3")}; Hotel fancy=new Hotel("Fancy Hotel",rfancy); Room[] rmayfair={new Room("A.1"),new Room("A.2"),new Room("A.3"),
new Room("B.1"),new Room("B.2"),new Room("B.3")}; Hotel mayfair=new Hotel("Mayfair Hotel", rmayfair); fancy.setSearchStrategy(new RandomSearchStrategy()); mayfair.setSearchStrategy(new FirstAvailableStrategy()); for(int i=0;i<10;i++)
System.out.print(fancy.bookRoom(fancy.searchRoom())+" "); System.out.println(""); for(int i=0;i<10;i++)
System.out.print(mayfair.bookRoom(mayfair.searchRoom())+" "); }
true false true false true true true false true false true true true true true true false false false false
sample output
55
General Solution
Strategy : declares common interface for all algorithmsConcreteStrategy : implements the interfaceContext :
- configured with ConcreteStrategyX object- typically provides interface to Strategy to receive input
56
Consequences
1. Helpful to organize algorithms in hierarchy (avoid code duplication)2. Why not subclass Context directly :
• not dynamically configurable• introduces many classes with limited differences• hard to reuse algorithm itself
3. Configurable behavior easier/cleaner than conditionals4. Runtime configuration allows to choose best algorithm for given
conditions5. Clients must know different strategies6. Communication overhead between Strategy and Context
(too much info passed to Strategy)7. Increased number of objects
57
Implementation
1. Interfacing between Context and StrategyOptions• pass all data as method arguments (can be too much)• pass Context reference to Strategy (tighter coupling)
2. Optional Strategy• If no Strategy specified : default behaviour• If Strategy present : use Strategy(e.g. Comparables in Java Collections Framework)
58
Motivation
Provide unified method to access sequentially objects in aggregating object, hiding underlying implementation
Usage :- support easy object traversal without revealing internals- support multiple ways to traverse object- support polymorphic iteration
Used in almost all data structure libraries(C++ STL, Java Collection Framework, .NET Collections)
59
General Solution
Iterator : defines interface for traversingConcreteIterator :
- implements Iterator interface, - keeps track of current position
Aggregate : defines interface for creating IteratorConcreteAggregate : implements Iterator creation
Java : inner classC++ : friend class
60
ConsequencesImplementation
Consequences1. Aggregates can be iterated through in various ways
(just implement the proper ConcreteIterator)2. The interface of the Aggregate becomes simpler3. Various Iterators can be active on same Aggregate simultaneously
Implementation1. Iteration control
• external : client requests Iterator to advance, does operation on current element, etc. -> complexer, general usage
• internal : client gives operation to Iterator, and Iterator appliesoperation on each element -> easier, but less applicable
2. Traversal algorithm• Iterator itself• Aggregate (Iterator is merely cursor)
61
Implementation3. Iterator robustness
- dangerous to change Aggregate while iterating-> expensive solution : make copy and iterate over copy
- robust Iterator-> gets notified by Aggregate when it changes-> adapts accordingly
4. Additional Iterator methods- skipTo, previous, ...
5. Iterator access- in C++ : friend class to allow access to Aggregate data- in Java : inner class
6. Iterating over Composites- external : requires storage of path through the recursive structure- internal : easier to implement (recursive call to itself)
7. NullIterator- trick to mark leaves of terminals
62
Motivation
Change object behavior based on internal stateAvoid testing on state variables in all methods
s1 s2 s3
if (state==s1) {...
} else if (state==s2) {...
} else {...
}Usage
- object behavior (heavily) depends on runtime state- a lot of methods would contain excessive state testing
63
Example : Room state
Room state diagram :- (not) available- dirty/clean
Methods :- book- unbook- guestEnters- clean
self-transitions not shown
65
Example : Room
class Room { private State s=new AvailableClean(); private String number; public void setState(State ss) {s=ss;} public Room(String n) {number=n;} public String toString() {return "["+number+" : "+s+"]";} public boolean book() {return s.book(this);} // delegate to state public boolean unbook() {return s.unbook(this);} public boolean clean() {return s.clean(this);} public boolean guestEnters() {return s.guestEnters(this);}}
66
Example : Stateinterface State { boolean book(Room r); boolean unbook(Room r); boolean clean(Room r); boolean guestEnters(Room r); }class AvailableClean implements State { public boolean book(Room r) { r.setState(new NotAvailableClean()); return true; } public boolean unbook(Room r) {return false;} public boolean clean(Room r) {return false;} public boolean guestEnters(Room r) {return false;} public String toString() {return "Available & Clean";}}
67
Example : State
class NotAvailableClean implements State { public boolean book(Room r) {return false;} public boolean unbook(Room r) { r.setState(new AvailableClean());
return true; } public boolean clean(Room r) {return false;} public boolean guestEnters(Room r) { r.setState(new NotAvailableDirty());
return true; } public String toString() {return "Not Available & Clean";}}
68
Example : State
class NotAvailableDirty implements State { public boolean book(Room r) {return false;} public boolean unbook(Room r) { r.setState(new AvailableDirty());
return true; } public boolean clean(Room r) { r.setState(new NotAvailableClean());
return true; } public boolean guestEnters(Room r) {return false;} public String toString() {return "Not Available & Dirty";}}
69
Example : State
class AvailableDirty implements State { public boolean book(Room r) {return false;} public boolean unbook(Room r) {return false;} public boolean clean(Room r) { r.setState(new AvailableClean()); return true; } public boolean guestEnters(Room r) {return false;} public String toString() {return "Available Dirty";}}// test code ...Room r=new Room("1.0");System.out.println(r);r.book();System.out.println(r);r.guestEnters();System.out.println(r);r.book();System.out.println(r);
70
General Solution
Context : refers ConcreteStateX, current state of the objectState : defines interface for behavior of Context objectConcreteState : implements associated behavior
71
Consequences
1. Localizes state-specific behavior-> but : more classes-> results in clearer code, especially for large number of states
2. Makes transitions explicit• more explicit that simply changing object variables• protection against inconsistent (or non-existing) states
3. Sharing of state objectsif no instance variables in state objects
72
Implementation
1. Performing state transitionsContext object : easy if sequence fixedState object :
- maps to state transition diagram- requires interface in Context to set state- but : introduces interdependencies in states
2. Table based state transitions- make table (current state, input, next state)- requires table lookup to determine next state+ change in state transition diagram is only change in data
(instead of changing code ...)3. Creation of state objects
- when needed- beforehand
73
Motivation
Capture object state WITHOUT violating encapsulationFacilitate restoring object current state to past state
Usage :- when public interface is not sufficient to capture state- facilitate checkpointing- facilitate undo commands- in Java : serialization can be used
75
Example : Memento Roomclass Housekeeper {/* as before */}class Room { private String number; private boolean available=true, cleaned=true; private ArrayList<Housekeeper> hk=new ArrayList<Housekeeper>(); // as before public RoomMemento createMemento() {return new RoomMemento();} public void setMemento(RoomMemento m) {
number=m.n;available=m.a;cleaned=m.c;hk=m.h;} class RoomMemento { private String n; private boolean a,c; private ArrayList<Housekeeper> h=new ArrayList<Housekeeper>(); private RoomMemento() { n=number;a=available; c=cleaned;h=(ArrayList)(hk.clone()); } }}
76
Example : Memento Room
public static void main(String[] args) { Room r=new Room("1.5"); Room.RoomMemento rm=r.createMemento(); r.book(); System.out.println(r); r.setMemento(rm); System.out.println(r); }
77
General Solution
Memento :- stores internal state of Originator (just enough to restore)- has two interfaces (wide and narrow)
Originator : - creates Memento - uses Memento to restore internal state
Caretaker :- manages Mementos- does not inspect or manipulate Memento state
widewide narrow
79
ConsequencesImplementationConsequences1. Maintain the encapsulation principle
Originator state not exposed to “everybody”2. Simplifies Originator
Version management of Originator done by client3. Memento potentially expensive
deep copies incur high overhead4. Language must support large and narrow interface5. Hidden costs
Caretaker does not know implications of storing MementosImplementation1. Language support for wide and narrow interface
- Java : inner class, package visibility, ...- C++ : declare friend class
2. Enrich Memento-interface to support incremental changesavoid copying everything ...