This pattern is called a Finite-State Machine [ ]:2An abstract machine consisting of a set of states including the initial state, a setof input events, a set of output events, and a stat
Trang 1VIETNAM NATIONAL UNIVERSITY HO CHI MINH CITY
UNIVERSITY OF SCIENCE
SEMINAR REPORT
STATE DESIGN PATTERN
Members of Group 05: Nguyễn Hữu Quốc Thắng
Nguyễn Chính Thông Phạm Trung Nghĩa Nguyễn Đức Thọ
Ho Chi Minh City, 16/12/2023
Trang 21.1 Problem 2 1.2 Limitations 4
2.1 Structure 5 2.2 Implementation 6
Trang 31 Introduction
1.1 Problem
Imagine we are writing a dictionary, and we want the user to be able to switch to different
“pages”, or modes of the app, such as a Word Search, Definition Search, View History, View Favorites, and Game Initially, one may decide to use a global variable to keep track of the state, and a switch statement, in order to switch to the mode that the user wants
One may write as follows [ ]:1
1 voidFrontendMain::start() {
2 // Logic to update the data for the current Page of the dictionary
3 switch(CurrentState::currentPage) {
4 casePage::DICT_WORD: {
5 word.update();
6 break;
7 }
8 casePage::DICT_DEF_SEARCH: {
9 def.update();
10 break;
11 }
12 casePage::DICT_FAVORITES: {
13 favorites.update();
14 break;
15 }
16 casePage::DICT_HISTORY: {
17 history.update();
18 break;
19 }
20 casePage::DICT_GAME: {
21 game.update();
22 break;
23 }
24 casePage::SINGLE_WORD_INFO: {
25 singleWordInfo.update();
26 break;
27 }
28 default:
29 break;
30 }
31
32 // Logic to draw the current Page of the dictionary
33 BeginDrawing();
2
Trang 434 {
35 ClearBackground(BG_COLOR_RGB);
36 switch(CurrentState::currentPage) {
37 casePage::DICT_WORD: {
38 word.draw();
39 break;
41 casePage::DICT_DEF_SEARCH: {
42 def.draw();
43 break;
45 casePage::DICT_FAVORITES: {
46 favorites.draw();
47 break;
49 casePage::DICT_HISTORY: {
50 history.draw();
51 break;
53 casePage::DICT_GAME: {
54 game.draw();
55 break;
57 casePage::SINGLE_WORD_INFO: {
58 singleWordInfo.draw();
59 break;
61 default:
62 break;
64
65 DrawTextureV(Resources::headerImage, {Header.x, Header.y}, WHITE);
66 DrawTextEx(Resources::titleFont,"THE DICTIONARY",
67 {500, Header.height / 2 - 30}, 50, 0, WHITE);
68 }
69 EndDrawing();
70 }
Trang 5This pattern is called a Finite-State Machine [ ]:2
An abstract machine consisting of a set of states (including the initial state), a set
of input events, a set of output events, and a state transition function The function takes the current state and an input event and returns the new set of output events and the next state
To simplify the concept:
At any given moment, there’s a finite number of states that the program can be in Within these states, the program can control the behavior of the system Depending on the current state, the program may decide whether to switch to other certain states, based on a set of rules These rules, called transitions, are also finite and predetermined State machines are usually predetermined with conditional statements (if or switch) that selects the appropriate behavior depending on the current state of the object
1.2 Limitations
For a project that only has a handful of states, like this one, it would be fine However, once we begin to add more and more states into the project, it becomes unreadable and harder
to maintain
For this particular project, we’ll need to add both the update() and draw() method when
we add a new “page” to the project Imagine this, but a bunch of pages more, like a thesaurus,
or word origin, or word of the day! It gets hard to navigate around easily
Additionally, in the future, imagine we want to also add more features into the program Like a version that the user has to pay to access the mentioned features We’d need to implement a check to check if the user has a valid license
Or like a word history feature We’d need to check if we have a network connection in order
to serve the user the latest version of the history, or if we need to use a local version And so on
It’s hard to predict all of the possible states and transitions for a single program
4
Trang 62 Definition
The state pattern is a behavioral software design pattern that allows an object to alter its behavior when its internal state changes [ ] This pattern is close to the concept of finite-state3 machines
The state pattern is used in computer programming to encapsulate varying behavior for the same object, based on its internal state This can be a cleaner way for an object to change its behavior at runtime without resorting to conditional statements and thus improve maintainability
2.1 Structure
The State pattern typically consists of the following key components:
• Context: Context stores a reference to one of the concrete state objects and delegates to
it all state-specific work The context communicates with the state object via the state interface The context exposes a setter for passing it a new state object
• State: The State interface declares the state-specific methods These methods should make sense for all concrete states because you don’t want some of your states to have useless methods that will never be called
• Concrete States: Concrete States provide their own implementations for the state-specific methods To avoid duplication of similar code across multiple states, you may provide intermediate abstract classes that encapsulate some common behavior.State objects may store a backreference to the context object Through this reference, the state can fetch any required info from the context object, as well as initiate state transitions Both context and concrete states can set the next state of the context and perform the actual state transition by replacing the state object linked to the context
The interaction between these components can be summarized as follows:
• The context maintains a reference to the current state object
• The context delegates the execution of a method to the current state object
• The current state object performs the behavior associated with that state
• The current state object may modify the state of the context, transitioning it to a different state if necessary
The State pattern promotes the encapsulation of state-specific behavior into separate classes, enabling the context object to be more flexible and adaptable to different states It allows for the addition of new states without modifying the context, and it improves code maintainability
by keeping behavior related to each state in separate classes
Trang 72.2 Implementation
1 Decide what class will act as the context It could be an existing class which already has the state-dependent code; or a new class, if the state-specific code is distributed across multiple classes
2 Declare the state interface Although it may mirror all the methods declared in the context, aim only for those that may contain state-specific behavior
3 For every actual state, create a class that derives from the state interface Then go over the methods of the context and extract all code related to that state into your newly created class While moving the code to the state class, you might discover that it depends on private members of the context There are several workarounds:
• Make these fields or methods public
• Turn the behavior you’re extracting into a public method in the context and call it from the state class This way is ugly but quick, and you can always fix it later
• Nest the state classes into the context class, but only if your programming language supports nesting classes
4 In the context class, add a reference field of the state interface type and a public setter that allows overriding the value of that field
5 Go over the method of the context again and replace empty state conditionals with calls
to corresponding methods of the state object
6 To switch the state of the context, create an instance of one of the state classes and pass
it to the context You can do this within the context itself, or in various states, or in the client Wherever this is done, the class becomes dependent on the concrete state class that it instantiates
3 Example
To better understand how to implement the State design pattern, let’s look at a simple example of a simple state of a traffic light:
6
Trang 81 Decide on the class that will act as the context It could be an existing class that already has state-dependent code or a new class if the state-specific code is distributed across multiple classes In this example, let’s create a class called TrafficLight to represent a traffic light
2 Declare the state interface The interface should include methods that may contain state-specific behavior In this example, we can create an interface called LightState with methods like turnOn(), turnOff(), and changeState()
1 classLightState{
2 public:
3 virtualvoidturnOn() = 0;
4 virtualvoidturnOff() = 0;
5 virtualvoidchangeState() = 0;
6 };
3 Create concrete classes for each actual state by deriving them from the state interface Move the state-specific code from the context class into these newly created state classes
1 classRedState: publicLightState {
2 public:
3 voidturnOn()override{
4 cout <<"Red light is on"<< endl;
5 }
6
7 voidturnOff()override{
8 cout <<"Red light is off"<< endl;
9 }
10
11 voidchangeState()override{
12 cout <<"Changing state from red to green"<< endl;
13 // Switch to GreenState
14 context->setState(newGreenState(context));
15 }
16 };
17
18 classGreenState: publicLightState {
19 public:
20 voidturnOn()override{
Trang 925 cout <<"Green light is off"<< endl;
26 }
27
28 voidchangeState()override{
29 cout <<"Changing state from green to yellow"<< endl;
30 // Switch to YellowState
31 context->setState(newYellowState(context));
32 }
33 };
34
35 classYellowState: publicLightState {
36 public:
37 voidturnOn()override{
38 cout <<"Yellow light is on"<< endl;
39 }
40
41 voidturnOff()override{
42 cout <<"Yellow light is off"<< endl;
43 }
44
45 voidchangeState()override{
46 cout <<"Changing state from yellow to red"<< endl;
47 // Switch to RedState
48 context->setState(newRedState(context));
49 }
50 };
4 In the context class (TrafficLight), add a reference field of the state interface type and
a public setter that allows overriding the value of that field
1 classTrafficLight{
2 private:
3 LightState* state;
4
5 public:
6 voidsetState(LightState* newState) {
7 state = newState;
8 }
9
10 voidperformAction() {
11 state->turnOn();
12 state->changeState();
8
Trang 1013 state->turnOff();
14 }
15 };
5 Now, to use the State design pattern, create an object of TrafficLight and set the initial state
1 intmain() {
2 TrafficLight trafficLight;
3
4 // Set initial state to RedState
5 trafficLight.setState(newRedState(&trafficLight));
6
7 // Perform actions
8 trafficLight.performAction();// RED -> GREEN
9 trafficLight.performAction();// GREEN -> YELLOW
10 trafficLight.performAction();// YELLOW -> RED
11
12 return0;
13 }
4 Real World Problems
• TV: ON or OFF
– ON: can press any button on the remote control depending on current function of TV
– OFF: can only press Power button on the remote control
• Phone: Silent, Vibration, Ringing
– Silent: No sound, no vibration when upcoming call
– Vibration: Only vibration …
– Ringing: Sound + vibration …
• Traffic Light: R, Y, G
– Each state, bulbs must release light with different wavelength, the timer must set
to a different period of time
Trang 115 Pros/Cons of State
• Pros:
– In the State design pattern, an object’s behavior is the result of the function of its state, and the behavior gets changed at runtime depending on the state This removes the dependency on the if/else or switch/case conditional logic
– Single Responsibility Principle Organize the code related to particular states into separate classes You may guarantee that each state has a clear and distinct duty
by encapsulating the behavior in multiple states, which can make your code easier
to maintain and alter
– Open/Closed Principle Introduce new states without changing existing state classes
or the context
– Simplify the code of the context by eliminating bulky state machine conditionals
• Cons:
– Applying the pattern can be overkill if a state machine has only a few states or rarely changes
– The State design pattern can be used when we need to change the state of the object
at runtime by inputting into it different subclasses of some State base class This circumstance is an advantage and disadvantage at the same time because we have
a clear separate State class with some logic and on the other hand the number of classes grows up
References
[1] N H Q Thang, L N Khoa, L P Minh, and N V H Thong, The Dictionary, CS163 Final Project, Aug 30, 2023 [Online] Available: https://github.com/Rookie001MC/Dictionary [2] Free Online Dictionary of Computing (Sep 22, 2001), [Online] Available: https://web archive.org/web/20171211180457/http://foldoc.org/finite+state+machine (visited on 12/06/2023)
[3] E Gamma, R Helm, R E Johnson, and J Vlissides, “Design Patterns, Elements of Resuable Object-Oriented Software,” in 2016, pp 305–313
10