Bertrand Meyer Lecture 6: More patterns: Visitor, Strategy, Chain, - - PDF document

bertrand meyer lecture 6 more patterns visitor strategy
SMART_READER_LITE
LIVE PREVIEW

Bertrand Meyer Lecture 6: More patterns: Visitor, Strategy, Chain, - - PDF document

Software Architecture Software Architecture Bertrand Meyer Lecture 6: More patterns: Visitor, Strategy, Chain, State, Command 1 Command 2 2 Command pattern - Intent Purpose Way to implement an undo-redo mechanism, e.g. in text y p g


slide-1
SLIDE 1

1

Software Architecture Software Architecture

Bertrand Meyer Lecture 6: More patterns: Visitor, Strategy, Chain, State, Command

slide-2
SLIDE 2

2

Command

2

slide-3
SLIDE 3

3

Command pattern - Intent

Purpose Way to implement an undo-redo mechanism, e.g. in text y p g

  • editors. [OOSC, p 285-290]

”Way to encapsulate a request as an object, thereby letting you parameterize clients with different t l t d t d bl requests, queue or log requests, and support undoable

  • perations.”

[Gamma et al., p 233] A li ti l

3

Application example EiffelStudio

slide-4
SLIDE 4

4

The problem

Enabling users of an interactive system to cancel the effect of the last command. Often implemented as “Control-Z”. Should support multi-level undo-redo, with no limitation pp ,

  • ther than a possible maximum set by the user

A good review of O-O techniques

4

slide-5
SLIDE 5

5

Working example: text editor

Notion of “current line”. Assume commands such as:

Insert line after current position Insert line before current position Delete current line Replace current line

S t li ith t if

Swap current line with next if any ...

This is a line oriented view for simplicity but the

5

This is a line-oriented view for simplicity, but the discussion applies to more sophisticated views

slide-6
SLIDE 6

6

Underlying class (from “business model”)

class EDIT_CONTROLLER feature text : LINKED_LIST [STRING] [ ] remove

  • - Remove line at current position.

require not off do text.remove d end put_right (line: STRING)

  • - Insert line after current position.

require not after do

6

do text.put_right (line) end ... end

slide-7
SLIDE 7

7

Key step in devising a software architecture

Finding the right abstractions Finding the right abstractions

(Interesting object types)

Here: The notion of “command”

7

slide-8
SLIDE 8

8

Keeping the history of the session

The history list:

Insert Insert Remove Swap Insert

Oldest Most recent

history : LINKED LIST [COMMAND]

8

history : LINKED_LIST [COMMAND]

slide-9
SLIDE 9

9

What’s a “command” object?

An instance of COMMAND includes information about one execution of a command by the user, sufficient to: execut on of a command by the user, suff c ent to

Execute the command Cancel the command if requested later

For example, in a delete command object, we need:

  • The position of the line being deleted
  • The content of that line

9

slide-10
SLIDE 10

10

General notion of command

deferred class COMMAND feature done: BOOLEAN execute

  • - Carry out one execution of this command.

deferred done: BOOLEAN

  • - Has this command been executed?

undo

  • - Cancel an earlier execution of this command.

: done end ensure already: done i

10

end deferred end require already: done

slide-11
SLIDE 11

11

Command class hierarchy *

execute* COMMAND undo*

+ +

+

*

deferred effective

DELETION INSERTION

execute+ undo+ li execute+ undo+ index

+

11

line index ... index ...

slide-12
SLIDE 12

12

A command class (sketch, no contracts)

class DELETION inherit COMMAND feature controller : EDIT_CONTROLLER A b i d l

  • - Access to business model

line : STRING

  • - Line being deleted

index : INTEGER

  • - Position of line being deleted

x ut execute

  • - Remove current line and remember it.

do line := controller.item ; index := controller.index controller.remove ; done := True end undo R i i l d li

12

  • - Re-insert previously removed line.

do controller.go_ith (index) controller.put_left (line) end end

slide-13
SLIDE 13

13

Executing a user command

decode_user_request if “Request normal command” then if Request normal command then “Create command object c corresponding to user request” history.extend (c) c.execute elseif “Request UNDO” then if not history.before then

  • - Ignore excessive requests

history.item.undo history.item.undo history.back end elseif “Request REDO” then if not history.is_last then -- Ignore excessive requests

history.forth history item execute

Insert Insert Remove Insert item

13

history.item.execute

end end

slide-14
SLIDE 14

14

Command pattern: overall architecture

history

*

commands

APPLICATION HISTORY

history

COMMAND

commands execute* undo* redo* execute can_undo, can_redo undo, redo undo_all, redo_all extend extend

+ COMMAND_1

execute+ undo+ d +

+ COMMAND_2

execute+ undo+ d +

14

redo+ redo+

slide-15
SLIDE 15

15

The undo-redo pattern

Has been extensively used Fairly easy to implement y y mp m Details must be handled carefully (e.g. some commands may not be undoable) Elegant use of O-O techniques Disadvantage: explosion of small classes g p In Java, can use “inner” classes.

15

slide-16
SLIDE 16

16

Using agents

For each user command, have two routines:

The routine to do it The routine to undo it!

16

slide-17
SLIDE 17

17

The history list using agents

The history list simply becomes a list of agents pairs: history : LINKED_LIST [TUPLE [PROCEDURE [ANY TUPLE] [PROCEDURE [ANY, TUPLE], PROCEDURE [ANY, TUPLE]] Basic scheme remains the same, but no need for command objects any th hi t li t i l t i t more; the history list simply contains agents.

Insert Insert Remove Swap Insert De- insert De- insert Re-insert Swap De- insert

17

slide-18
SLIDE 18

18

Executing a user command (before)

decode_user_request if “Request is normal command” then if Request is normal command then “Create command object c corresponding to user request” history.extend (c) c.execute elseif “Request is UNDO” then if not history before then Ignore excessive requests if not history.before then -- Ignore excessive requests history.item.undo history.back end elseif “Request is REDO” then

Insert Insert Remove Insert item

18

if not history.is_last then -- Ignore excessive requests history.forth

  • history. item.execute

end end

slide-19
SLIDE 19

19

Executing a user command (now)

“Decode user_request giving two agents do_it and undo_it ” if “Request is normal command” then q history.extend ([do_it, undo_it ]) do_it.call ([]) elseif “Request is UNDO” then if not history.before then

Insert Insert Remove Swap De- insert De- insert Re- insert Swap

y history.item.item (2) .call ([]) history.back end elseif “Request is REDO” then if not history is last then

19

if not history.is_last then history.forth history.item.item (1) .call ([]) end end

slide-20
SLIDE 20

20

Command - Consequences

Command decouples the object that invokes the operation from the one that knows how to perform it. Commands are first-class objects. They can be manipulated and extended like any other object. You can assemble commands into a composite command. It's easy to add new Commands, because you don't have to change existing classes.

20

slide-21
SLIDE 21

21

Command - Participants

Command

declares an interface for executing an operation. g p

Concrete command

defines a binding between a Receiver object and an action. implements Execute by invoking the corresponding operation(s) on

Receiver.

Client

creates a ConcreteCommand object and sets its receiver.

Invoker

asks the command to carry out the request. asks the command to carry out the request.

Receiver

knows how to perform the operations associated with carrying out a

  • request. Any class may serve as a Receiver.

21

slide-22
SLIDE 22

22

Some design patterns

Creational

Ab t

t F t Behavioral

Chain of Responsibility Abstract Factory Builder Factory Method Prototype Singleton Chain of Responsibility Command (undo/redo) Interpreter Iterator Mediator Memento

Structural

Adapter Bridge Composite Decorator Memento Observer State Strategy Template Method Visitor Façade Flyweight Proxy Visitor

slide-23
SLIDE 23

23

Visitor

23

slide-24
SLIDE 24

24

Visitor - Intent

“Represents an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.” [Gamma et al., p 331]

Static class hierarchy Need to perform traversal operations on

corresponding data structures

Avoid changing the original class structure

24

Avoid changing the original class structure

slide-25
SLIDE 25

25

Visitor application example

Set of classes to deal with an Eiffel or Java program (in EiffelStudio, Eclipse ...) , p ) Or: Set of classes to deal with XML documents (XML_NODE, XML_DOCUMENT, XML_ELEMENT, XML_ATTRIBUTE, XML_CONTENT…) One parser (or several: keep comments or not…) M f tt Many formatters:

Pretty-print Compress Convert to different encoding G

t d t ti

25

Generate documentation Refactor …

slide-26
SLIDE 26

26

Inheritance hierarchy

FIGURE * center * display* rotate* OPEN_ FIGURE * CLOSED_ FIGURE * SEGMENT POLYLINE POLYGON perimeter * perimeter + perimeter + + + SEGMENT POLYLINE POLYGON ELLIPSE RECTANGLE TRIANGLE perimeter ++ diagonal

... ...

+ side2 side1

26

CIRCLE SQUARE perimeter ++

perimeter ++

* deferred + effective ++ redefined

perimeter ++

slide-27
SLIDE 27

27

Polymorphic data structures

figs : LIST [FIGURE ]

(POLYGON) (CIRCLE) (POLYGON) (CIRCLE) (ELLIPSE)

from from figs start until figs after loop

27

loop figs item

display

figs forth end

slide-28
SLIDE 28

28

The dirty secret of O-O architecture

Is it easy to add types (e.g. LOZENGE) to

FIGURE * center * display* rotate*

( g ) existing operations

OPEN_ FIGURE * CLOSED_ FIGURE * SEGMENT POLYLINE POLYGON ELLIPSE perimeter * perimeter + perimeter + + + CIRCLE RECTANGLE TRIANGLE SQUARE perimeter ++ diagonal

... ...

side2 perimeter ++ side1

What about the reverse: adding an operation to existing types?

CIRCLE SQUARE perimeter ++ perimeter

slide-29
SLIDE 29

29

Vehicle example

+ * VEHICLE + TAXI + BUS

We want to add external functionality, for example:

29

Maintenance Schedule a vehicle for a particular day

slide-30
SLIDE 30

30

Vehicle operations

schedule (v : VEHICLE, d: DAY)

  • - Set up schedule of v for d.

require

Why is this approach bad ?

maintain (v : VEHICLE)

  • - Perform maintenance on v.

require require exists: v /= Void do if attached {BUS } v as b then b schedule (d ) end require exists: v /= Void do if attached {BUS } v as b then b send_to_depot end if attached {TAXI } v as t then t put_on_call (d ) end ... Other cases ... if attached {TAXI } v as t then t send_to_garage (Next_monday) end Other cases

30

end end ... Other cases ... end end

slide-31
SLIDE 31

31

The original view

CLIENT visit T_TARGET Client (calls)

31

( )

slide-32
SLIDE 32

32

Visitor participants

Target classes Example: BUS TAXI Example: BUS, TAXI Client classes Application classes that need to perform

  • perations on target objects
  • perations on target objects

Visitor classes Written only to smooth out the collaboration between the other two

32

between the other two

slide-33
SLIDE 33

33

Visitor participants

Visitor General notion of visitor Concrete visitor Specific visit operation, applicable to all target elements Target General notion of visitable element Concrete target Concrete target Specific visitable element

33

slide-34
SLIDE 34

34

The original view

CLIENT visit T_TARGET Client (calls) ( )

slide-35
SLIDE 35

35

The visitor ballet

CLIENT t accept (v ) v T_TARGET V_VISITOR v T_visit (Current ) Client (calls) Client (knows about) _ ( )

slide-36
SLIDE 36

36

Visitor class hierarchies

* accept*

v T_visit (Current )

+ VISITOR visit_bus* visit_tram* * VEHICLE + TAXI + BUS + MAINTENANCE _VISITOR + SCHEDULE _VISITOR accept+ accept+ visit_taxi + visit_taxi + visit_bus + visit_bus +

36

Target classes Visitor classes

slide-37
SLIDE 37

37

The maintenance visitor

class MAINTENANCE_VISITOR inherit VISITOR VISITOR feature -- Basic operations visit_taxi (t : TAXI)

  • - Perform maintenance operations on t.

do do t send_to_garage (Next_monday) end visit_bus (b: BUS )

  • - Perform maintenance operations on b

37

Perform maintenance operations on b. do b send_to_depot end end

slide-38
SLIDE 38

38

The scheduling visitor

class MAINTENANCE_VISITOR inherit VISITOR VISITOR feature -- Basic operations visit_taxi (t : TAXI)

  • - Perform scheduling operations on t.

do do ... end visit_bus (b: BUS )

  • - Perform scheduling operations on b

38

Perform scheduling operations on b. do ... end end

slide-39
SLIDE 39

39

Changes to the target classes

class BUS inherit VEHICLE deferred class VEHICLE feature accept (v : VISITOR)

  • - Apply bus visit to v.

do v.visit_bus (Current) end feature ... Normal VEHICLE features ... accept (v : VISITOR) A l hi l i it t end end

  • - Apply vehicle visit to v.

deferred end end class TAXI inherit VEHICLE feature accept (v : VISITOR)

39

accept (v : VISITOR)

  • - Apply taxi visit to v.

do v.visit_taxi (Current) end end

slide-40
SLIDE 40

40

The full picture

* VISITOR accept* visit_bus* visit tram* * VEHICLE

v T_visit (Current )

+ TAXI + BUS + MAINT_ VISITOR + SCHEDULE_ VISITOR visit_tram

Target classes

+ V_VISITOR

Visitor classes

+ T v T_visit (Current) accept +accept + visit_taxi + visit_taxi + visit_bus + visit_bus + visit_taxi + accept +

t accept (v )

v

visit_bus +

Example client calls:

40

CLIENT

bus21.accept (maint_visitor) fleet.item.accept (maint_visitor)

slide-41
SLIDE 41

41

Visitor - Consequences

Makes adding new operations easy Gathers related operations, separates unrelated ones Avoids assignment attempts

Better type checking

Adding new concrete element is hard g

Does the visitor pattern observe the Open-Closed Principle ?

41

slide-42
SLIDE 42

42

Visitor vs dynamic binding

Dynamic binding:

Easy to add types Hard to add operations

Visitor:

Easy to add operations Hard to add types

42

slide-43
SLIDE 43

43

The visitor pattern

* VISITOR accept* visit_bus* visit tram* * VEHICLE

v T_visit (Current )

+ TAXI + BUS + MAINT_ VISITOR + SCHEDULE_ VISITOR visit_tram

Target classes

+ V_VISITOR

Visitor classes

+ T v T_visit (Current) accept +accept + visit_taxi + visit_taxi + visit_bus + visit_bus + visit_taxi + accept +

t accept (v )

v

visit_bus +

Example client calls:

43

CLIENT

bus21.accept (maint_visitor) fleet.item.accept (maint_visitor)

slide-44
SLIDE 44

44

The Visitor Library

One generic class VISITOR [G] e.g. maintenance_visitor: VISITOR [VEHICLE] Actions represented as agents actions: LIST [PROCEDURE [ANY, TUPLE [G]]] No need for accept features No need for accept features

visit determines the action applicable to the given

element For efficiency

44

Topological sort of actions (by conformance) Cache (to avoid useless linear traversals)

slide-45
SLIDE 45

45

Visitor Library interface (1/ 2)

class VISITOR [G] create make feature {NONE} -- Initialization make

  • - Initialize actions

Initialize actions. feature -- Visitor visit (an_element: G)

  • - Select action applicable to an_element.

require an element not void: an element /= Void

45

an_element_not_void: an_element /= Void feature -- Access actions: LIST [PROCEDURE [ANY, TUPLE [G]]]

  • - Actions to be performed depending on the element
slide-46
SLIDE 46

46

Visitor Library interface (2/ 2)

feature -- Element change extend (action: PROCEDURE [ANY, TUPLE [G]])

  • - Extend actions with action
  • - Extend actions with action.

require action_not_void: action /= Void ensure

  • ne_more: actions.count = old actions.count + 1

inserted: actions.last = action append (some_actions: ARRAY [PROCEDURE [ANY, TUPLE [G]]])

  • - Append actions in some_actions
  • - to the end of the actions list.

require

some_actions_not_void: some_actions /= Void

( )

46

no_void_action: not some_actions.has (Void) invariant actions_not_void: actions /= Void no_void_action: not actions.has (Void) end

slide-47
SLIDE 47

47

Using the Visitor Library

maintenance_visitor: VISITOR [BORROWABLE] create maintenance_visitor.make maintenance_visitor.append ([ agent maintain_taxi, agent maintain_trolley

,

]) maintain_taxi (a_taxi: taxi) ... maintain trolley (a trolley: TROLLEY) ... agent maintain_tram

47

maintain_trolley (a_trolley: TROLLEY) ... maintain_tram (a_tram: BUS) ...

slide-48
SLIDE 48

48

Topological sorting of agents (1/ 2)

* BORROWABLE * VEHICLE * BUS + TRAM + TROLLEY

48

slide-49
SLIDE 49

49

Topological sorting of agents (2/ 2)

schedule_visitor.extend (agent schedule_taxi) schedule_visitor.extend (agent schedule_bus) schedule visitor extend (agent schedule vehicle) schedule_visitor.extend (agent schedule_vehicle) schedule_visitor.extend (agent schedule_tram) schedule_visitor.extend (agent schedule_trolley)

For agent schedule_a (a: A) and schedule_b (b: B), if A conforms to B then position of schedule a is before position of schedule b in

schedul e_taxi schedule_ vedio_tram schedule_ bus schedule_ vehicle schedule_ tram

B, then position of schedule_a is before position of schedule_b in the agent list

1 5 2 4 3

schedule_visitor.visit (a_bus)

49

slide-50
SLIDE 50

50

Strategy

50

slide-51
SLIDE 51

51

Strategy - Intent

Purpose “Define a family of algorithms, encapsulate each one, and y g p make them interchangeable. Strategy lets the algorithm vary independently from clients that use it”. [Gamma et al., p 315] Example application selecting a sorting algorithm on-the-fly

51

slide-52
SLIDE 52

52

Life without strategy: a sorting example

feature -- Sorting

sort (il : LIST [INTEGER ]; st : INTEGER) sort (il : LIST [INTEGER ]; st : INTEGER)

  • - Sort il using algorithm indicated by st.

require il /= Void is_strategy_valid (st) do do inspect st when binary then … when quick then … when bubble then …

What if a new algorithm is needed ?

wh n u th n … else … end ensure a_list_sorted: … end

52

slide-53
SLIDE 53

53

Strategy pattern: overall architecture

*

STRATEGY

+

CONTEXT

do_something do_something* strategy

+ STRATEGY_A

+

STRATEGY_B

+

STRATEGY_C

do_something+ do_something+ do_something+ 53

slide-54
SLIDE 54

54

Class STRATEGY

deferred class STRATEGY feature -- Basic operation do_something

  • - Do something (perform some algorithm).

deferred end end end

54

slide-55
SLIDE 55

55

Class CONTEXT (1/ 3)

class CONTEXT create make feature {NONE} -- Initialization make (s: like strategy)

  • - Make s the new strategy.

require s /= Void do strategy := s strategy := s ensure strategy_set: strategy = s end

55

slide-56
SLIDE 56

56

Class CONTEXT (2/ 3)

feature – Basic operations do_something

  • - Do something (call algorithm cooresponding to strategy ).

do strategy.do_something end set strategy (s: like strategy) set_strategy (s: like strategy)

  • - Set strategy to s.

require s /= Void do strategy := s ensure strategy = s end

56

slide-57
SLIDE 57

57

Class CONTEXT (3/ 3)

feature {NONE} – Implementation strategy: STRATEGY

  • - Strategy to be used

invariant strategy_not_void: strategy /= Void end

57

slide-58
SLIDE 58

58

Using strategy pattern

sorter_context: SORTER_CONTEXT bubble_strategy: BUBBLE_STRATEGY quick_strategy: QUICK_STRATEGY create sorter_context.make (bubble_strategy)

Now, what if a new algorithm is needed ?

hash_strategy: HASH_STRATEGY ( gy) sorter_context.sort (a_list) sorter_context.set_strategy (quick_strategy) sorter_context.sort (a_list) sorter_context.set_strategy (hash_strategy) sorter_context.sort (a_list)

58

slide-59
SLIDE 59

59

Strategy - Consequences

  • Families of related algorithms
  • An alternative to subclassing
  • An alternative to subclassing
  • Eliminate conditional statements
  • A choice of implementations
  • Clients must be aware of different Strategies
  • Communication overhead between Strategy and Context
  • Increased number of objects

59

slide-60
SLIDE 60

60

Strategy - Participants

Strategy

declares an interface common to all supported algorithms.

Concrete strategy

implements the algorithm using the Strategy interface.

Context

is configured with a concrete strategy object. maintains a reference to a strategy object. 60

slide-61
SLIDE 61

61

Chain of responsibility

61

slide-62
SLIDE 62

62

Chain of responsibility - Intent

Purpose “Avoid[s] coupling the sender of a request to its receiver by Avoid[s] coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. [It] chain[s] the receiving objects and pass[es] the request along the chain until an object handles it.” [Gamma et al., p 223] [ , p ] Example application A GUI event is passed from level to level (such as from button to dialog and then to application)

62

slide-63
SLIDE 63

63

Chain of responsibility: overall architecture

* HANDLER[G]

next handle can_handle* do_handle* handled

APPLICATION + INTERMEDIATE_ HANDLER[G] + FINAL_HANDLER[G]

set_next

63

can_handle+ do_handle+ can_handle+ do_handle+

slide-64
SLIDE 64

64

Class HANDLER [ G] (1/ 3)

deferred class HANDLER [G] create default_create, make feature {NONE } -- Initialization

make (n : like next)

  • - Set next to n.

do

next := n

ensure ensure

next_set: next = n

end feature -- Access

next : HANDLER [G]

  • - Successor in the chain of responsibility

feature Status report

64

feature -- Status report

can_handle (r : G): BOOLEAN deferred end

  • - Can this handler handle r?

handled: BOOLEAN

  • - Has request been handled?
slide-65
SLIDE 65

65

Class HANDLER [ G] (2/ 3)

feature -- Basic operations handle (r : G)

  • - Handle r if can_handle otherwise forward it to next.

If no next set handled to False

  • - If no next, set handled to False.

do if can_handle (r ) then do_handle (r ) ; handled := True else if next /= Void then next.handle (r ) ; handled := next.handled next.handle (r ) ; handled next.handled else handled := False end end ensure can_handle (r ) implies handled (not can_handle (r ) and next /= Void) implies handled = next.handled ( h dl ( ) d V d) l h dl d

65

(not can_handle (r ) and next = Void) implies not handled end

slide-66
SLIDE 66

66

Class HANDLER [ G] (3/ 3)

feature -- Element change set_next (n : like next)

  • - Set next to n.

t n t t n. do next := n ensure next_set: next = n end feature {NONE} – Implementation do_handle (r : G)

  • - Handle r.

require can_handle: can_handle (r) d f d

66

deferred end end

slide-67
SLIDE 67

67

Using chain of responsibility

btn_help_provider: BUTTON_HELP_HANDLER [CLICK_REQUEST] dialog_help_provider: DIALOG_HELP_HANDLER [CLICK_REQUEST] win_help_provider: WINDOW_HELP_HANDLER [CLICK_REQUEST] create win_help_provider create dialog_help_provider.make (win_help_provider) create btn_help_provider.make (dialog_help_provider) _ p_p ( g_ p_p ) btn_help_provider.handle (a_click_request)

67 btn_helper_provider dialog_help_provider win_help_provider

slide-68
SLIDE 68

68

Chain of responsibility - Consequences

Reduced coupling

An object only has to know that a request will be handled j y q "appropriately“. Both the receiver and the sender have no explicit knowledge of each other

Added flexibility in assigning responsibilities to objects

Abilit t dd h ibiliti f h dli Ability to add or change responsibilities for handling a request by adding to or otherwise changing the chain at run- time

Receipt isn't guaranteed p g

the request can fall off the end of the chain without ever being handled

68

slide-69
SLIDE 69

69

Chain of responsibility - Participants

Handler

defines an interface for handling requests. (optional) implements the successor link.

Concrete handler

handles requests it is responsible for.

q p

can access its successor. if the Concrete handler can handle the request, it does so; otherwise it

forwards the request to its successor.

Client

initiates the request to a Concrete handler object on the chain.

69

slide-70
SLIDE 70

70

State

70

slide-71
SLIDE 71

71

State - Intent

Purpose “Allows an object to alter its behavior when its internal j state changes. The object will appear to change its class”. [Gamma et al., p 305] Application example:

add attributes without changing class state machine simulation

71

slide-72
SLIDE 72

72

State: overall architecture

*

STATE

+

CONTEXT

do_something do_something* state context

+ INITIAL_STATE

+

INTERMEDIATE _STATE

+

FINAL_STATE

do_something+ do_something+ do_something+

What’s the difference between state and strategy ?

72

slide-73
SLIDE 73

73

Class CONTEXT

class CONTEXT … feature – Basic operations do_something

  • - Do something depending on the state.

do state do something state .do_something end feature {NONE} -- Implementation state: STATE Current state

  • - Current state

some_other_state: STATE

  • - Other managed state

end

73

slide-74
SLIDE 74

74

Class STATE

deferred class STATE … feature – Basic operations do_something

  • - Do something

deferred end feature -- Access context: CONTEXT

  • - Context where current is used

… end

74

slide-75
SLIDE 75

75

Class CONCRETE_STATE

class CONCRETE_STATE inherit STATE feature – Basic operations d hi do_something

  • - Do something

do … context.set_state (context.some_other_state) end end

75

slide-76
SLIDE 76

76

Using state (1/ 5): Class WEBSITE_CONTEXT

class WEBSITE_CONTEXT feature – Basic operations login login

  • - Login.

do state.login end logout

  • - Logout.

do state.logout end visit_url (a_url: URL)

  • - Visit URL a_url.

do state.visit (a_url) end

76

slide-77
SLIDE 77

77

Using state (2/ 5): Class WEBSITE_CONTEXT

feature {NONE} -- Implementation state: ACCOUNT_STATE

  • - Current state
  • - Current state

feature {ACCOUNT_STATE} -- Implementation loggedin_state, loggedout_state: like state

  • - States

set_state (a_state: like state)

  • - Logout state

require a_state_not_void: a_state /= Void do state := a_state ensure state_set: state = a_state end end

77

slide-78
SLIDE 78

78

Using state (3/ 5): Class ACCOUNT_STATE

deferred class ACCOUNT_STATE feature – Basic operations feature – Basic operations login deferred end logout deferred end visit_url (a_url: URL) i require a_url_not_void: a_url /= Void deferred end feature{NONE} – Implementation f atur {NONE} mp m ntat on context: WEBSITE_CONTEXT

  • - Context

… end

78

slide-79
SLIDE 79

79

Using state (4/ 5): Class LOGIN_STATE

class LOGGEDIN_STATE inherit inherit ACCOUNT_STATE feature – Basic operations login do end l t logout do context.set_state(context.loggedout_state) end visit_url (a_url: URL) _ ( _ ) do

  • - Go to URL.

end end

79

slide-80
SLIDE 80

80

Using state (5/ 5): Class LOGOUT_STATE

class LOGGEDOUT_STATE inherit inherit ACCOUNT_STATE feature – Basic operations login do t t t t t ( t t l di t t ) context.set_state(context.loggedin_state) end logout do end visit_url (a_url: URL) _ ( _ ) do

  • - Disallow visit.

end end

80

slide-81
SLIDE 81

81

State - Consequences

It localizes state-specific behavior and partitions behavior for different states It makes state transitions explicit State objects can be shared

81

slide-82
SLIDE 82

82

State - Participants

Context

defines the interface of interest to clients. maintains an instance of a Concrete state subclass that defines the

current state.

State

defines an interface for encapsulating the behavior associated with a particular state of the Context.

Concrete state

each subclass implements a behavior associated with a state of the Context

82