1 1.mediator 2.observer 3.chain of responsibilitiy 4.command 5.strategy 6.iterator 7.state 8.memento

79
1 1. Mediator 2. Observer 3. Chain of Responsibilitiy 4. Command 5. Strategy 6. Iterator 7. State 8. Memento

Upload: blake-craze

Post on 15-Dec-2015

217 views

Category:

Documents


0 download

TRANSCRIPT

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 ?

6

Example : Hotel cleaning

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(); } } }

11

The mediated Hotel

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

22

Example : Cleaning notification

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)

25

Observer solution

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

28

General solution

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

30

General solution

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.

39

Example : book hotel rooms

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

47

General Solution

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

64

Example : Room statestate.book(this)

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

74

Example : Memento Room

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

78

General Solution

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 ...