程序设计模式 —— State 状态模式
我应该如何阅读?
本文将使用优雅的文字风格来告诉你什么是状态模式。
注意:
1.在阅读本文之前请保证你已经掌控了 面对对象的思想与 多态的基本概念,否则将难以理解。
2.本文实现将用C++实现,你不一定必须学会C++,这些代码都有非常丰富的注释和简单的语法。
3.请不要跳着看,除非你已经学会。
那么现在开始吧
或许你会以为是类的各种状态,其实差不多。但是还有各种行为
允许一个对象在其内部状态改变时改变它的行为。实例化的对象看起来似乎修改了它的类
首先,状态,顾名思义你应该就差不多明白。它可以表示一个类中的状态,但是不仅仅只是状态。
它也包括了 行为,有点儿类似于策略模式,但是又不是策略模式。
我一直坚信。这个设计模式,只需要仅仅一张图片即可完成说明:这张三个片段代表飞机的三个不同状态
你懂了吗?根据日常生活的常识,你应该明白飞机这几种状态,但是我相信你应该还不太明白如何实现具体代码。
你也应该明白 “没有动力” 的时候是不能飞行的。
你也应该明白 “正在飞行” 的时候是不能再飞行的。
正是因为如此,我们就可以直接在不同的状态子类,实现不同的方法,比如 “没有动力” 的时候,如果使用 “起飞” 成员函数,将会提示没有动力,起飞失败。
而 “没有飞行” 的时候却是可以 使用 “起飞” 成员函数。
那么我应该具体怎么做?
实现的代码很简单。并且有丰富的注释,希望你能理解。
大致框架图:
飞机类是可以使用 任何一个 状态类,表示不同的状态。
注意:如果你不会 C++,也没有关系,”Virtual” 关键字你可以无视,至于成员函数后面有一个 "=0",你可以理解为抽象方法,子类必须实现它,用Java的思想去看待代码
状态类的基类
下面我们来具体实现:基类永远都是这么简单,对吧?
/* 状态类的基类 抽象类*/
class State
{
public:
State()
{ };
virtual ~State()
{ };
virtual void fly()=; //起飞 =0是纯虚函数,可以理解为子类必须实现的 抽象方法
virtual void stopfly()=; //停止飞行,降落
virtual void up()=; //拉升飞行高度
virtual void down()=; //拉低飞行高度 };
实现状态类的各个子类
然后我们应该来实现 各种状态了
代码有点多,但是都是很容易的。而且有丰富的注释。。
//状态类: 正在飞行 状态类
class StateFlying : public State
{
public:
StateFlying()
{ };
virtual ~StateFlying()
{ };
virtual void fly()
{
//因为飞机正在飞行,所以不能再度起飞
cout << "ERROR: Can't do this!! You are not 'stopfly'! " <<endl;
}; //起飞
virtual void stopfly()
{
//正在飞行的时候当然可以降落
cout << "INFO: OK! stopfly" << endl;
}; //停止飞行,降落
virtual void up()
{
//目前的状况当然可以这样做
cout << "INFO: OK! up" << endl;
}; //拉升飞行高度
virtual void down()
{
//目前的状况当然可以这样做
cout << "INFO: OK! down" << endl;
}; //拉低飞行高度
}; //状态类: 停机状态
class StateNotFly : public State
{
public:
StateNotFly()
{ };
virtual ~StateNotFly()
{ };
virtual void fly()
{
//因为是 停机状态,所以是可以起飞的
cout << "INFO: OK! " << endl;
}; //起飞
virtual void stopfly()
{
//你难道可以 停机之后 再停机么?
cout << "ERROR: Can't do this!! You are not 'Flying'! " <<endl;
}; //停止飞行,降落
virtual void up()
{
//停机的时候这些空中动作就算了吧
cout << "ERROR: Can't do up!! You are not 'Flying'! " <<endl;
}; //拉升飞行高度
virtual void down()
{
//停机的时候这些空中动作就算了吧
cout << "ERROR: Can't do down!! You are not 'Flying'! " <<endl;
}; //拉低飞行高度
}; //状态类: 没有动力状态
class StateNotPower : public State
{
public:
StateNotPower()
{ };
virtual ~StateNotPower()
{ };
virtual void fly()
{
//没有动力了,无法起飞!
cout << "ERROR: Can't do fly!! You are not Power! " <<endl;
}; //起飞
virtual void stopfly()
{
//没有动力了,赶紧降落
cout << "INFO: OK! stopfly" << endl;
}; //停止飞行,降落
virtual void up()
{
//没有动力,你是没法爬升的,等死吧!
cout << "ERROR: Can't do up!! You are not Power! " <<endl;
}; //拉升飞行高度
virtual void down()
{
//没有了动力了,但是可以 滑翔下降
cout << "INFO: OK! down" << endl;
}; //拉低飞行高度
}; /*
如果你学过其他设计模式,或者了解代码复用,你可能会说上面的代码可以复用(我是指各个成员函数中的输出),完全不必要这样写。
这里仅仅只是为了举例,尽量少的牵扯到其他。
*/
这样,我们的三个状态就好了。从代码中你也可以看见一件事情,每个状态都有自己的各自的具体处理。
但是你现在可能会问,为什么要浪费时间写这么多看起来都是差不多的功能呢?
其实这样的话,你在飞机类里面就会出现一种现象,就是需要一个个判断当前的状态然后做相应的事情。类似于这样:
//假设你要执行停飞,但是不使用状态模式,将会有这种代码的出现
if(/*当前不是飞行ing*/)
{
//提示不能停飞
}
if(/*当前是飞行*/)
{
//执行停飞
}
if(/*当前没有动力*/)
{
//不能停飞
}
这种代码不但枯燥无趣,而且难以维护。如果哪天你加了一个“即将坠机”的状态,你需要修改每个类的每个方法。。。
实现飞机类 AirPlane 类
好了,回归正题,我们来实现飞机!看看飞机是如何不需要进行 状态 判断就可以直接用:
/*这是 飞机类 这个类才是正在 在用上面的各种类*/
class AirPlane
{
private:
string name;
State *state; //状态 public:
AirPlane()
{
this->state = new StateNotPower(); //初始化状态为 “没有动力” 状态
};
~AirPlane()
{
delete this->state; //记得释放喔~
};
void setName(const char* name)
{
this->name = name; //复制
}
void setState(State * state)
{
delete this->state; //先释放原来的
this->state = state; //改成新的 状态
};
void fly()
{
cout << "[AirPlane][" << this->name << "] ";
this->state->fly();
}; //起飞
void stopfly()
{
cout << "[AirPlane][" << this->name << "] ";
this->state->stopfly();
}; //停止飞行,降落
void up()
{
cout << "[AirPlane][" << this->name << "] ";
this->state->up();
}; //拉升飞行高度
void down()
{
cout << "[AirPlane][" << this->name << "] ";
this->state->down();
}; //拉低飞行高度
//你可以发现,我们将具体的实现全部交给了 子类去实现,我们完全不必管到底如何进行。
//当然了,如果你会策略模式,或许你能更加灵活运用,策略模式与本模式很相似。
};
你可以看见,我们已经将方法全部委托给了 状态 类。对吧。这有什么问题?
你根本无需在乎飞机到底是什么状态,完全就是直接用 状态类 的方法就好了。
现在我们来战斗吧
“作为 Pattern Art Online (AR)空战游戏的 元老玩家。你接到上级命令需要赶快去前线实行救援,你的队友几乎已经死绝了,你感到万分悲伤,你决定报仇”
“但是 你本来就很少上前线,因为你已经普升到 军长了,但是你手上已经没有任何战斗飞行员了,你必须亲自上阵,因为如果一旦退缩的话,后面就是你的家乡”
#include "State.h" using namespace std; int main(int argc, char const *argv[])
{
/*
你实例化了一架 新的飞机,这个时候 作为 Pattern Art Online 游戏的 元老玩家。
你需要赶过去支援你的 队友!
前线目前已经非常紧张,导致你起飞的动作僵硬无比。
*/
/*好的,我创建了一架飞机*/
AirPlane *air = new AirPlane();
/*随便取个名字,Alier Two 号*/
air->setName("Alier Tow");
/*起飞吧!我要赶快去 救我的队友*/
air->fly(); /*输出: ERROR: Can't do fly!! You are not Power!*/
/*该死,太紧张了,毕竟时间紧,你,就你,快加满油!*/
air->setState(new StateNotFly()); //状态改成一切就绪,但没有正在飞行
/*很好,油满了,给我拉升!*/
air->up(); /*输出: ERROR: Can't do up!! You are not 'Flying'!*/
/*可恶,忘记先发动 螺旋桨了。。。*/
air->fly(); /*输出: INFO: OK!*/
/*哈哈哈,飞起来了!*/
air->setState(new StateFlying()); //状态改成 飞行ing
/*给我飞高点*/
air->up(); /*输出: INFO: OK! up*/ /* ---五个小时的飞行后---*/ /*咦?怎么回事,螺旋桨不转了?*/
air->setState(new StateNotPower());
/*卧槽,忘记带后备用油了,我可是要飞到 北美洲去啊!总部,总部!请求加油机支援!!!*/
/*可恶。给我飞高点!!!*/
/* ---距离地面还剩 800米--- */
air->up(); /*输出: ERROR: Can't do up!! You are not Power!*/
/*不...不要啊!不管什么,给我飞起来啊!!!*/
air->fly(); /*救命啊: ERROR: Can't do fly!! You are not Power!*/
/* ---即将坠机--- */
/* ...砰... */
/* --- You die--- */ cin.get(); delete air; /*可怜的你,还没有飞到前线就坠机了,真是.....*/
return ;
}
输出:
那么,你现在明白了?状态模式。你可以轻松的复用。甚至可以定义N个状态,定义个N不同的飞机,并且飞机与状态这之间却可以轻松的反复重用!
因为状态都继承了 State 抽象类,而飞行则只管使用,定义状态,而不需要管理不同状态下的不同行为。
就这样结束了?
“你的队友对你十分失望,你的上司对你的飞行技术感到质疑,这是一个不好的现象,这意味着你很有可能要被逐出 【Fly!Fly!Fly!】战队。”
“那么。你不准备做什么?”
“听说 Pattern Art Online (VR)角色扮演类游戏开始了,你的队友貌似挺感兴趣,你决心要利用黑客技术来帮助自己取得队友的信任。”
故事后续情节请看:《程序设计模式——策略模式》
最后
但是要注意的一点,不是说有了这个模式,就必须要加进去使用,程序会更棒。
设计模式要与你的程序相互和谐,不能写个 “HelloWorld” 程序都用到了设计模式。
总的一句话,设计模式不是规则,而是你随时可以改变的模式。这也是很多设计模式书籍强调的一点。
不论对你是否有帮助,还是谢谢您的耐心查看。如有错误之处,还望指教。
程序设计模式 —— State 状态模式的更多相关文章
- C++设计模式-State状态模式
State状态模式作用:当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类. UML图如下: State类,抽象状态类,定义一个接口以封装与Context的一个特定状态相关的行为. ...
- JAVA设计模式--State(状态模式)
状态模式(State Pattern)是设计模式的一种,属于行为模式. 定义(源于Design Pattern):当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类. 状态模式主要 ...
- [C++设计模式] state 状态模式
<head first 设计模式>中的样例非常不错,想制造一个自己主动交易的糖果机,糖果机有四个状态:投入钱不足,投入钱足够,出售糖果,糖果售罄. 糖果机的当前状态处于当中不同的状态时,它 ...
- 【转】设计模式 ( 十七) 状态模式State(对象行为型)
设计模式 ( 十七) 状态模式State(对象行为型) 1.概述 在软件开发过程中,应用程序可能会根据不同的情况作出不同的处理.最直接的解决方案是将这些所有可能发生的情况全都考虑到.然后使用if... ...
- 设计模式 ( 十七) 状态模式State(对象行为型)
设计模式 ( 十七) 状态模式State(对象行为型) 1.概述 在软件开发过程中,应用程序可能会根据不同的情况作出不同的处理.最直接的解决方案是将这些所有可能发生的情况全都考虑到.然后使用if... ...
- 北风设计模式课程---状态模式State(对象行为型)
北风设计模式课程---状态模式State(对象行为型) 一.总结 一句话总结: 状态模式 具体状态的行为在具体的状态类中就解决,不用交给外部做判断.实质是将多条件判断弄成了多个类,在不同的类中做判断 ...
- 乐在其中设计模式(C#) - 状态模式(State Pattern)
原文:乐在其中设计模式(C#) - 状态模式(State Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 状态模式(State Pattern) 作者:webabcd 介绍 允 ...
- 设计模式---状态变化模式之state状态模式(State)
前提:状态变化模式 在组建构建过程中,某些对象的状态经常面临变化,如何对这些变化进行有效的管理?同时又维持高层模块的稳定?“状态变化”模式为这一个问题提供了一种解决方案. 典型模式 状态模式:Stat ...
- 设计模式21:State 状态模式(行为型模式)
State 状态模式(行为型模式) 动机(Motivation) 在软件构建过程中,某些对象的状态如果改变,其行为也会随之而发生变化,比如文档处于只读状态,其支持的行为和读写状态的行为就可能完全不同. ...
随机推荐
- HBase修改压缩格式及Snappy压缩实测分享
一.要点 有关Snappy的相关介绍可参看Hadoop压缩-SNAPPY算法,如果想安装Snappy,可以参看Hadoop HBase 配置 安装 Snappy 终极教程. 1. HBase修改Tab ...
- Linux设备驱动剖析之Input(四)
static void input_pass_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) ...
- VS2005 / windows sdk7.1配置
VS2005工程需要调用一些后期VS带的库 1. VS2005 安装顺序 1.vs20052.msdn(optional)3.VS80sp1-KB926601-X86-ENU_SP1.exe4.VS8 ...
- 一次受限于操作系统进程数的OOM
在64bit机上跑应用,结果进程刚起来就挂,就刚起来就挂..还OOM,还fork不出新进程,尼玛,这什么情况? 1. 如果是应用层面OOM,那么不应该任何命令都不被执行了,不应该OS直接crash掉. ...
- 如何重置CentOS 7的Root密码?设置CentOS 7的Root密码的方法与步骤
- winedt设置自动显示行号[latex]
options--preferences--appearance 在show line numbers for modes下面的文本框里添加;Tex 这样新建或者打开tex文件的时候就自动显示行号了( ...
- ios开发人员mac空间不够用的解决办法
有时候,当我们的mac硬盘空间不够用的时候,我们查看“用户”文件夹,发现这个文件夹占用了很大的存储空间,可是当我们一个一个查看这个文件夹下的子文件夹所占的存储空间大小并把这些存储空间大小加起来的时候却 ...
- Java版的Quartz表达式生成器,同时适用于Quartz.net(免费下载)
Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用.Quartz可以用来创建简单或为运行十个,百个, ...
- 【Android】Handler、Looper源码分析
一.前言 源码分析使用的版本是 4.4.2_r1. Handler和Looper的入门知识以及讲解可以参考我的另外一篇博客:Android Handler机制 简单而言:Handler和Looper是 ...
- css3背景颜色渐变
<!DOCTYPE html> <html> <head> <meta http-equiv="content-type" content ...