Skip to content

Commit 1b973c3

Browse files
committed
[STATE]: Added ressources for the State pattern.
1 parent acf6410 commit 1b973c3

File tree

3 files changed

+72
-3
lines changed

3 files changed

+72
-3
lines changed

behavioral-patterns/state/README.md

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,52 @@
1-
# TODO
1+
Also known as **Objects for states**.
22

3-
Stay tuned, this section will be completed shortly !
3+
# Intend
4+
5+
As stated in [_GoF_, p305](https://fr.wikipedia.org/wiki/Design_Patterns) :
6+
> Allow an object to alter its behaviour when its internal state changes. The object ill appear to change its class.
7+
8+
You should use the _State_ pattern in the following cases :
9+
- You want to change an object's behaviour at runtime depending on its state.
10+
- When you have a class polluted with massive conditionals that alter how it behaves.
11+
- When you have a lot of duplicate code across similar states and transitions of a condition-based state machine.
12+
13+
# How it's done
14+
15+
![UML](UML.jpg)
16+
17+
**Participants**
18+
19+
-_Context_
20+
- Interface of interest to clients.
21+
- Maintains an instance of a _ConcreteState_ subclass that defines the current state and its behaviour.
22+
- _State_ Interface for the behaviour associated with a particular state of the _Context_.
23+
- _ConcreteStates_ implement a behaviour associated with a state of the _Context_.
24+
25+
**How to implement**
26+
27+
1. **Declare** the _State_ interface - that is, the behaviour that depends on the state.
28+
2. **Create** a _ConcreteState_ subclass for every identified state of the _Context_. Implement the behaviours of those states.
29+
3. **Add** a reference field of the _State_ in the _Context_ class and its associated setter.
30+
4. **Replace** where needed in the methods of the _Context_ the conditionals with the corresponding calls to the _State_ object.
31+
32+
33+
Note : UML class diagram taken from [**here**](https://upload.wikimedia.org/wikipedia/commons/e/ec/W3sDesign_State_Design_Pattern_UML.jpg)
34+
35+
# Pros & cons
36+
37+
**Pros**
38+
39+
- **Open/Closed principle** : It is easy to introduce new _ConcreteStates_ without breaking any existing code.
40+
- **Single responsability principle** : Separate states/behaviours are defined within separate classes.
41+
- Simplify the code of the _Context_ by eliminating a lot of conditionals.
42+
43+
**Cons**
44+
45+
- Can be overkill if there are only a few states and they should never change.
46+
47+
# Notes
48+
49+
Here are some _usefull ressources_ :
50+
- [**w3sdesign**](http://w3sdesign.com/#gf)
51+
- A [**Refactoring guru**](https://refactoring.guru/design-patterns/state) article.
52+
- A complete example [**here**](http://www.vishalchovatiya.com/state-design-pattern-in-modern-cpp/)

behavioral-patterns/state/UML.jpg

41.3 KB
Loading

behavioral-patterns/state/state.cpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,38 +7,58 @@
77
#include <algorithm>
88
#include <memory>
99

10+
// ------------------ State ------------------ //
11+
/*!
12+
* @brief State class
13+
* Defines an interface to encapsulate the behaviour
14+
* associated to a particular state of the Context.
15+
*/
1016
class IWritingState {
1117
public:
1218
virtual void Write(std::string p_words) = 0;
1319
};
1420

21+
// ------------- ConcreteStates ------------- //
22+
/*!
23+
* @brief ConcreteState subclasses
24+
* Implements the behaviour of a particular state of the Context.
25+
*/
1526
class UpperCase : public IWritingState {
27+
public:
1628
void Write(std::string p_words) override {
1729
std::transform(p_words.begin(), p_words.end(), p_words.begin(), ::toupper);
1830
std::cout << p_words << std::endl;
1931
}
2032
};
2133

2234
class LowerCase : public IWritingState {
35+
public:
2336
void Write(std::string p_words) override {
2437
std::transform(p_words.begin(), p_words.end(), p_words.begin(), ::tolower);
2538
std::cout << p_words << std::endl;
2639
}
2740
};
2841

2942
class Default : public IWritingState {
43+
public:
3044
void Write(std::string p_words) override { std::cout << p_words << std::endl; }
3145
};
3246

47+
/*!
48+
* @brief Context
49+
* Interface of interest for the client.
50+
* Maintains a reference to its current state (ConcreteState)
51+
*/
3352
class TextEditor {
3453
public:
3554
TextEditor(const std::shared_ptr<IWritingState>& p_state): m_state(p_state) {}
3655
void SetState(const std::shared_ptr<IWritingState>& p_state) { m_state = p_state; }
3756
void Type(const std::string& p_words) { m_state->Write(p_words); }
3857
private:
39-
std::shared_ptr<IWritingState> m_state;
58+
std::shared_ptr<IWritingState> m_state; /*!< Current state */
4059
};
4160

61+
// --------------- Client code --------------- //
4262
int main()
4363
{
4464
TextEditor editor(std::make_shared<Default>());

0 commit comments

Comments
 (0)