博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
状态模式
阅读量:4618 次
发布时间:2019-06-09

本文共 3052 字,大约阅读时间需要 10 分钟。

定义

状态模式(State Pattern)允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。

状态模式通用类图

State——抽象状态角色

接口或抽象类,负责对象状态定义,并且封装环境角色以实现状态切换。

ConcreteState——具体状态角色

每一个具体状态必须完成两个职责:本状态的行为管理以及趋向状态处理,通俗地说,就是本状态下要做的事情,以及本状态如何过渡到其他状态。

Context——环境角色

定义客户端需要的接口,并且负责具体状态的切换。

状态模式的优点:

结构清晰,避免了过的switch…case或者if…else语句的使用,避免了程序的复杂性,提供系统的可维护性。实质上状态模式所做的,就是将与特定状态相关的行为局部化,并且将不同状态的行为分割开来。State将特定的状态行为都放入一个对象中,由于所有与状态相关的代码都存在于某一个ConcreteState类中, 所以通过定义新的子类可以很容易的增加新的状态和转换[DP]

缺点:

其实增加新的子类并不容易,因为在状态对象中,只定义了向下一状态转换的接口函数,而并不知道其可以由哪些状态转换来,所以,添加新的状态子类时,转至下一状态的功能好实现,但转来的功能就不好实现了,需要去逐个修改可以转换至该状态的所有状态以添加转换至此的功能。导致这一问题的原因是,各状态子类之间的相互转换是各自独立实现的,这其实增加了状态子类之间的耦合度。

举例:

来自《大话设计模式》以电梯为例,其有四个状态:运行,停止,开门,关门,相互之间转换关系如图:

C++实现,部分细节与《大话设计模式》中的java实现不同

#include 
using namespace std;class Lift;class LiftState{ //定义抽象状态角色protected: Lift *lift; //定义环境角色(这里是电梯),封装状态的变化引起的功能变化protected: void SetContext(Lift *lift){
this->lift = lift;}; //实现功能或进行状态切换的函数声明 virtual void open(){}; virtual void close(){}; virtual void run(){}; virtual void stop(){}; friend class Lift;};class Lift{ //环境角色private: //隐藏状态对象 static LiftState * const statesSet[]; //指针数组 LiftState *liftstate; //当前电梯状态public: enum STATETYPE{OPENING,CLOSING,RUNNING,STOPPING}; //此处枚举类型的值顺序应该与statesSet的初始化顺序对应public: void setLiftState(STATETYPE state) { this->liftstate=statesSet[state]; //由枚举类型映射到 this->liftstate->SetContext(this); } void open(){ this->liftstate->open(); } void close(){ this->liftstate->close(); } void run(){ this->liftstate->run(); } void stop(){ this->liftstate->stop(); }};class OpeningState:public LiftState{public: void open(){ //当前状态下的核心任务 cout<<"电梯门开启..."<
setLiftState(lift->CLOSING); //先切换状态 lift->close(); //再执行动作 } //开门状态下是不能运行也不需要停止的,所以这两个功能就使用基类里的默认实现了,即什么也不做 //什么也不做是一种消极的处理,有时候可能需要返回提示信息以告诉用户操作错误,或者做些其他处理。};class ClosingState:public LiftState{public: void close(){ cout<<"电梯门关闭..."<
setLiftState(lift->OPENING); //先切换状态 lift->open(); //再执行动作 } void run(){ lift->setLiftState(lift->RUNNING); lift->run(); } void stop(){ lift->setLiftState(lift->STOPPING); lift->stop(); }};class RunningState:public LiftState{public: void run(){ cout<<"电梯上下运行..."<
setLiftState(lift->STOPPING); lift->stop(); }};class StoppingState:public LiftState{ void stop(){ cout<<"电梯停止了..."<
setLiftState(lift->OPENING); //先切换状态 lift->open(); //再执行动作 } void run(){ lift->setLiftState(lift->RUNNING); lift->run(); }};LiftState * const Lift::statesSet[]={
new OpeningState,new ClosingState,new RunningState,new StoppingState};int main(){ Lift lift; lift.setLiftState(lift.CLOSING); lift.open(); lift.close(); lift.run(); lift.stop(); return 0;}

运行结果:

转载于:https://www.cnblogs.com/xingchenfeng/p/3795434.html

你可能感兴趣的文章
转:架构师实践日|亿级短视频应用秒拍的架构实践
查看>>
解决FreeBSD ssh出现Using keyboard-interactive authentication
查看>>
JavaScript(3)
查看>>
替换文本是什么
查看>>
LIS+二分法
查看>>
指针与引用
查看>>
JavaScript---网络编程(9-1)--DHTML技术演示(2-1)-表格创建的几种方式
查看>>
Codeforces-940D. Alena And The Heater
查看>>
Hive查询
查看>>
解决 vs2010 联接sql 2005 时 报错未能加载文件或程序集“Microsoft.SqlServer.Management.Sdk.Sfc...
查看>>
函数初识
查看>>
Java时间日期格式转换Date转String和String转Date
查看>>
Linux简介
查看>>
django查询操作
查看>>
易语言启动窗口上的"关闭"按钮被按下,应该怎样写事件?
查看>>
【做题】CFedu41G. Partitions——推式子
查看>>
jdk环境变量配置
查看>>
C语言回顾-内存管理和指针函数
查看>>
三、freemarker数据、模版指令
查看>>
wm_concat函数的排序问题
查看>>