Download presentation
Presentation is loading. Please wait.
1
CSE3311 Software Design State Pattern
2
Copyright Head First Design Patterns Chapter 10
3
Problem You are developing a program to keep track of movies for a video store. There are three movie types: regular, children’s, and new releases. The charge for a movie will depend on the length of the rental and its type. Also, customers receive a number of frequent renter points that depend on the type of the movie rented. We need the ability to calculate the price and frequent renter points that accrue to a customer renting a movie. Develop a BON diagram demonstrating the classes you might include in this system along with their relationships. Do not be concerned with user interface classes.
4
Looks like a Statechart?
5
First Design class MOVIE1 create make feature {NONE} – Initialization make(n,t: STRING) is do name := n type := t end feature name: STRING type: STRING
6
First Design require positive_days: days_rented >= 0 do
price(days_rented: INTEGER): REAL is require positive_days: days_rented >= 0 do if type.is_equal("REG") then Result := 2 if days_rented > 2 then Result := Result + (days_rented - 2) * 1.5 end elseif type.is_equal("NEW") then Result := days_rented * 3 elseif type.is_equal("CHI") then Result := 1.5 if days_rented > 3 then Result := Result + (days_rented - 3) * 1.5
7
First Design How will we change the state from NEW to REG?
points: INTEGER -- frequent renter points do if type.is_equal("REG") then Result := 100 elseif type.is_equal("NEW") then Result := 200 elseif type.is_equal("CHI") then Result := 150 end set_type(t: STRING) type := t.twin end -- class MOVIE1 How will we change the state from NEW to REG?
8
First Design test class
make local m1, m2, m3: MOVIE1 do -- Design 1: It works but changes are very cumbersome print("Design1%N") create m1.make("Casablanca", "REG") create m2.make("Bambi", "CHI") create m3.make("The Lord of the Rings", "NEW") print (m1.price(2).out + "%N") print (m2.price(1).out + "%N") print (m3.price(5).out + "%N") print (m3.points.out + " points%N") m3.set_type ("REG") print("The new price for The Lord of the Rings is: ") print (m3.points.out + " points%N%N") end
9
Critique? Suppose we need to add a new state ADVENTURE_MOVIE?
price is calculated differently frequent renter points is calculated different Will need to change multiple places (price and points routine logic) there may be many more type dependent routines such as special_discount etc. Single Choice Principle Violated
10
Design Two price* points*
Change state (e.g.state ”reg”, “chi”) from class STRING to a class MOVIE2 Use polymorphism and dynamic binding to delegate calculation of price and points to MOVIE2 Adding a new state is easy Removes if … elseif … elseif … end statements in class MOVIE1
11
Second Design test class
make is -- Creation procedure. local m1, m2, m3: MOVIE1 m4, m5, m6: MOVIE2 do -- Design 1: It works but changes are very cumbersome -- Design2: Takes advantage of polymorphism print("Design2%N") create {REGULAR} m4.make("Casablanca") create {CHILDRENS} m5.make("Bambi") create {NEW} m6.make("The Lord of the Rings") print (m4.price(2).out + "%N") print (m5.price(1).out + "%N") print (m6.price(5).out + "%N") print (m6.points.out + " points%N") print("How to change 'Lord of Rings' to regular???%N%N") end Position of Single Choice price & points in MOVIE2 (polymorphism + dynamic binding)
12
Final Design! Delegate price & points to MOVIE_STATE price points
set_type price* points* Dynamic change of the state Single choice happens here
13
Final Design Single Choice Delegate price & points to MOVIE_STATE
class MOVIE3 create make feature {NONE} – Initialization make(n,t: STRING) do name := n; set_type(t) end feature name: STRING type: MOVIE_STATE set_type (t: STRING) do if t.is_equal("NEW") then create {NEW_STATE} type elseif t.is_equal("REG") then create {REGULAR_STATE} type elseif t.is_equal("CHI") then create {CHILDRENS_STATE} type end price (days_rented: INTEGER): REAL is do Result := type.price(days_rented) end points: INTEGER do Result := type.points end Single Choice Delegate price & points to MOVIE_STATE
14
Final Design test class
Design 1: It works but changes are very cumbersome Design2: Takes advantage of polymorphism, but what if "The Lord of the Rings" is no longer a NEW movie? Design 3: Polymorphism is now delegated to the state object. Adding a new state is trivial make local m7, m8, m9: MOVIE3 do create m7.make("Casablanca", "REG") create m8.make("Bambi", "CHI") create m9.make("The Lord of the Rings", "NEW") print (m7.price(2).out + "%N") print (m8.price(1).out + "%N") print (m9.price(5).out + "%N") print (m9.points.out + " points%N") m9.set_type ("REG") print("The new price for The Lord of the Rings is: ") end
15
What have we done so far? Localized the behaviour of each state in its own class (encapsulate what varies) Removed troublesome if statements that are difficult to maintain Polymorphism & Code is easier to understand Closed each state for modification and yet left the video store open to extension (open closed principle)
16
State Pattern: allows an object to alter its behaviour when its internal state changes. The object will appear to change its class By encapulating each state we localize any changes that will need to be made (e.g. price and points) to that state (behaviour)
19
State vs. Strategy The class diagrams are similar but they differ in intent State Behaviours are constantly changing over time and the client (context) knows very little about how those different behaviours work Encapsulate behaviours in state objects and set change in the context Alternative to putting a lot of conditionals in the context Strategy Client knows quite a lot about what behaviour (state) is most appropriate e.g. we know that a mallard duck has typical flying behaviour and a decoy duck never flies Change in state less usual Flexible alternative to subclassing
22
adding new states
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.