设计模式学习总结:状态模式(State)
来源:互联网 发布:淘宝品质退款包括哪些 编辑:程序博客网 时间:2024/06/06 16:42
1.场景分析
假如我们需要为一家糖果公司制作一个糖果机。糖果机的运行机制如下面的状态图所示:
从图中我们知道,状态机有四个状态:没有25分钱、有25分钱、售出糖果、糖果售罄。所以我们可以通过一个枚举类型来定义每个状态:
enum class MachineState { SOLD_OUT, NO_QUARTER, HAS_QUARTER, SOLD };
其有四个操作:投入25分、退回25分、转动曲柄、发放糖果,可以分别用四个函数来表示这四种动作:
void insertQuarter(); void ejectQuarter(); void turnCrank(); void dispense();
最后我们写出来的糖果机如下所示:
class GumballMachine{public: enum class MachineState { SOLD_OUT, NO_QUARTER, HAS_QUARTER, SOLD }; void insertQuarter() { switch (_state) { case MachineState::SOLD_OUT: cout << "you can not insert a quarter, the machine is sold out" << endl; break; case MachineState::NO_QUARTER: cout << "you insert a quarter" << endl; _state = MachineState::HAS_QUARTER; break; case MachineState::HAS_QUARTER: cout << "you can not insert another quarter" << endl; break; case MachineState::SOLD: cout << "please wait, we are already giving you a gumball" << endl; break; default: break; } } void ejectQuarter() { switch (_state) { case MachineState::SOLD_OUT: cout << "you can not eject, you haven't inserted a quarter" << endl; break; case MachineState::NO_QUARTER: cout << "you haven't inserted a quarter" << endl; break; case MachineState::HAS_QUARTER: cout << "Quarter returned" << endl; _state = MachineState::HAS_QUARTER; break; case MachineState::SOLD: cout << "sorry, you already turned the crank" << endl; break; default: break; } } void turnCrank() { switch (_state) { case MachineState::SOLD_OUT: cout << "you turned, but there are no gumballs" << endl; break; case MachineState::NO_QUARTER: cout << "you turned, but there is no quarter" << endl; break; case MachineState::HAS_QUARTER: cout << "you turned" << endl; _state = MachineState::SOLD; dispense(); break; case MachineState::SOLD: cout << "turning twice doesn't get you another gumball" << endl; break; default: break; } } void dispense() { switch (_state) { case MachineState::SOLD_OUT: cout << "no gumball dispensed" << endl; break; case MachineState::NO_QUARTER: cout << "you need to pay first" << endl; break; case MachineState::HAS_QUARTER: cout << "no gumball dispensed" << endl; break; case MachineState::SOLD: cout << "A gumball come rolling out the slot" << endl; --_gumballCount; if (_gumballCount == 0) _state = MachineState::SOLD_OUT; else _state = MachineState::NO_QUARTER; break; default: break; } }private: MachineState _state = MachineState::NO_QUARTER; int _gumballCount = 0;};
从上述代码中,我们可以看到大量的switch语句,状态管理十分混乱,而且如果新添加一个状态将十分艰难,代码变得难以扩展。这时我们可以通过状态模式来改善我们的代码设计。
首先我们定义一个State基类,在这个类中,糖果机的每个动作都有一个对应的方法。
class MachineState{public: virtual void insertQuarter(){} virtual void ejectQuarter(){} virtual void turnCrank(){} virtual void dispense(){}};
然后我们为机器的每个状态实现状态类。这些类负责在对应状态下进行机器的行为。
最后,我们要摆脱旧的条件代码,取而代之的方法是将动作委托到状态类。
最后我们重构后的糖果机如下图:
#include <iostream>using namespace std;class MachineState{public: virtual void insertQuarter(){} virtual void ejectQuarter(){} virtual void turnCrank(){} virtual void dispense(){}};class GumballMachine{public: void setState(MachineState *state) { if (_state) delete _state; _state = state; } int getGumballCount() { return _gumballCount; } void releaseGumball() { --_gumballCount; } void insertQuarter(){ if (!_state) return; _state->insertQuarter(); } void ejectQuarter(){ if (!_state) return; _state->ejectQuarter(); } void turnCrank(){ if (!_state) return; _state->turnCrank(); } void dispense(){ if (!_state) return; _state->dispense(); }private: MachineState *_state = nullptr; int _gumballCount = 0;};class NoQuarterState : public MachineState{public: NoQuarterState(GumballMachine *machine) :_machine(machine){} void insertQuarter() override { _machine->setState(new HasQuarterState(_machine)); }private: GumballMachine * _machine = nullptr;};class HasQuarterState : public MachineState{public: HasQuarterState(GumballMachine *machine) :_machine(machine){} void ejectQuarter() override { _machine->setState(new SoldState(_machine)); }private: GumballMachine * _machine = nullptr;};class SoldState : public MachineState{public: SoldState(GumballMachine *machine) :_machine(machine){} void dispense() override { _machine->releaseGumball(); if (_machine->getGumballCount() > 0) _machine->setState(new NoQuarterState(_machine)); else _machine->setState(new SoldOutState(_machine)); }private: GumballMachine * _machine = nullptr;};class SoldOutState : public MachineState{public: SoldOutState(GumballMachine *machine) :_machine(machine){}private: GumballMachine * _machine = nullptr;};
2.意图
允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。
3.适用性
- 一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为。
- 一个操作中含有庞大的多分支条件语句,且这些分支依赖于对象的状态,这些状态通常用一个或多个枚举常量表示。
4.结构
Context:环境,定义客户端感兴趣的接口。
State:环境所处的状态,定义Context与特定状态相关的行为。
5.效果
1>它将与特定状态相关的行为局部化,并且将不同状态的行为分割开。State模式将所有与一个特定状态相关的行为都放入一个对象中。因为所有与状态相关的代码都存在于某一个State子类中,所以通过定义新的子类可以很容易的增加新的状态和装换。这样我们就避免了使用一大堆相似的条件语句来管理状态,但是同时也引入了另一个问题,就是增加了子类的数量,相对于当个类的实现来说不够紧凑。我们让每一个状态“对修改关闭”,而让context“对扩展开放”。
2>它使得状态转换显示化。当一个对象仅以内部数据值来定义当前状态时,其状态仅表现在对一些变量的赋值,这不够明确。为不同的状态引入独立的对象使得装换变得更加明确。
3>State对象可以被共享,如果State对象没有实例变量——即它们表示的状态完全以它们的类型来编码——那么各Context可以共享一个状态对象。当状态以这种方式被共享时,它们必定是没有内部状态而只有行为的轻量级对象(Flyweight)。
6.实现
1>谁定义状态转换。有两种选择,第一种是在Context中实现所有状态转换的操作,另一种是由State子类自身来指定它们的后续状态以及何时进行转换。通常第二种方法更加灵活,但是这样做则一个State子类至少拥有另一个State子类的相关信息,增加了子类之间的耦合性。我们前面例子中采用的第二种实现方法。
2>基于表的另一种方法。
3>创建和销毁State对象。有两种选择:(1)仅当需要State对象时才创建它们并在使用后销毁。(2)提前创建它们并且始终不销毁它们。当上下文不经常改变状态时,第一种比较适合,如果状态改变很频繁,则第二种比较合适。
7.代码示例
我们来实现一个表示网络连接的类TCPConnection,并用状态模式来实现其处于不同的网络状态。
#include <iostream>using namespace std;class TCPConnection;class TCPState{public: virtual void activeOpen(TCPConnection *tcpConnection){} virtual void passiveOpen(TCPConnection *tcpConnection){} virtual void close(TCPConnection *tcpConnection){} virtual void send(TCPConnection *tcpConnection){} virtual void acknowledge(TCPConnection *tcpConnection){} virtual void synchronize(TCPConnection *tcpConnection){}protected: void changeState(TCPConnection *tcpConnection, TCPState *tcpState);};class TCPCloseState : public TCPState{public: static TCPCloseState *create() { return new TCPCloseState(); } void activeOpen(TCPConnection *tcpConnection);};class TCPOpenState : public TCPState{public: static TCPOpenState *create() { return new TCPOpenState(); } //省略其他状态转化实现 ...};class TCPConnection{public: TCPConnection() { _state = TCPCloseState::create(); } void activeOpen() { if (!_state) return; _state->activeOpen(this); } void passiveOpen() { if (!_state) return; _state->passiveOpen(this); } void close() { if (!_state) return; _state->close(this); } void send() { if (!_state) return; _state->send(this); } void acknowledge() { if (!_state) return; _state->acknowledge(this); } void synchronize() { if (!_state) return; _state->synchronize(this); }private: friend TCPState; void changeState(TCPState *state); TCPState *_state = nullptr;};void TCPState::changeState(TCPConnection *tcpConnection, TCPState *tcpState){ tcpConnection->changeState(tcpState);}void TCPCloseState::activeOpen(TCPConnection *tcpConnection){ changeState(tcpConnection, TCPOpenState::create());}
- 设计模式学习总结:状态模式(State)
- 设计模式学习之------State模式(状态模式)
- 设计模式总结之State Pattern(状态模式)
- 设计模式入门学习 状态State模式
- 设计模式学习笔记--状态(State)模式
- 设计模式----State(状态)
- 设计模式学习笔记二十二(State状态模式)
- 设计模式学习--状态模式(State Pattern)
- 【设计模式】学习笔记14:状态模式(State)
- 【设计模式】学习笔记14:状态模式(State)
- 设计模式学习--状态模式(State Pattern)
- State(状态)设计模式
- 设计模式之State(状态模式)
- 设计模式 (十六)状态模式(State)
- 【设计模式】之状态模式(State)
- java设计模式-状态模式(State)
- 设计模式之状态模式(State)
- 设计模式(16):状态模式 State
- SpringBoot之数据访问
- 【C/C++】C++11新特性:std::bind
- 产品的三层境界:工具-平台-生态
- Cron表达式
- 网管系统 絮叨
- 设计模式学习总结:状态模式(State)
- 【代码分享】一种异常值检测方法、原理 (基于箱线图)
- 网络相关配置笔记之route -n 的详细解释(linux)
- 作用域生存周期理解笔记
- html-webpack-plugin 移除代码中的空格
- 还记得在开发工具中传统的jar包导入方式吗?
- water shader
- Skip List(跳跃表)与ConcurrentSkipListMap
- 数据结构1