赞
踩
目录
状态模式是一种行为型设计模式。当某个对象在不同状态下有不同行为时使用,在该模式中,我们将对象的不同状态
定义成不同的类,在这些状态类下有它们各自的行为,然后在客户端调用 Context 类,而不需要显示地去设置各个状态之间的转换
- 允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。
该模式的本质是对象的状态改变时,会引起其行为的改变,从外部看就像该对象所对应的类的行为发生了改变一样。例如,电灯的开关,在灯的不同状态下(亮或灭),按下开关时,灯的行为是不一样的。或者说汽车,只有在车停下的时候才能打开车门,行驶的时候是不可以开门的。这就是状态的不同就会导致不同的行为。
- 从UML来看,UML的结构似乎和策略模式是一模一样的,但是两种模式的本质却是完全不同的。策略模式中的策略(或者说是行为)是因为根据外界需要而使用不同的策略来完成需求;而状态模式中,是因为其自身状态改变,而影响了自身的一系列行为的改变。虽然这个状态的变更可能是外界引发的。
- 抽象状态角色(State),负责定义各个状态有哪些行为,该抽象状态包含所有具体状态的方法。并且封装环境角色,帮助切换状态。
- 具体状态角色(ConcreteState),实现具体状态下可以执行的行为, 每一个具体状态类必须完成两个职责:该类本状态下要做的事情,以及如何执行到其他具体状态类的状态。
- 环境角色(Context) ,该角色是客户端要调用的接口,在该类内部维护一个ConcreteState子类的一个实例,可以负责具体状态的切换(客户端不知道状态的切换)。
用C++ 代码实现大话设计模式本章代码:
- #include<iostream>
- using namespace std;
-
- class State;
- class ForenoonState;
- class NoonState;
- class AfternonnState;
- class EveningState;
- class SleepingState;
- class RestState;
- class Work;
-
- // 抽象状态角色,负责定义各个状态有哪些行为,该抽象状态包含所有具体状态的方法。并且封装环境角色,帮助切换状态。
- class State
- {
- public:
- virtual void writeprogram(Work* w) = 0;
- virtual ~State() = default;
- };
- // Contex 角色,在该类内部维护一个ConcreteState子类的一个实例,可以负责具体状态的切换
- class Work
- {
- private:
- State* current;
- double m_hour;
- bool m_finish = false;
- public:
- Work();
- ~Work();
- void setHour(double hour) { m_hour = hour; }
- double getHour() { return m_hour; }
-
- void setFinish(bool finish) { m_finish = finish; }
- bool getFinish() { return m_finish; }
- void SetState(State* s)
- {
- delete current;
- current = s;
- }
- void WorkProgram()
- {
- current->writeprogram(this);
- }
- };
-
- // 下面都是具体的状态类,每一个具体状态类必须完成两个职责:该类本状态下要做的事情,以及如何执行到其他具体状态类的状态。
- class ForenoonState :public State
- {
- public:
- void writeprogram(Work* w)override;
- };
-
- class NoonState :public State
- {
- public:
- void writeprogram(Work* w)override;
- };
-
- class AfternoonState :public State
- {
- public:
- void writeprogram(Work* w)override;
- };
-
- class EveningState :public State
- {
- public:
- void writeprogram(Work* w)override;
- };
-
- class SleepingState :public State
- {// 睡眠状态
- public:
- void writeprogram(Work *w)override;
-
- };
-
- class RestState :public State
- {// 下班休息状态
- public:
- void writeprogram(Work *w)override;
-
- };
-
- Work::Work()
- {
- current = new ForenoonState();
- }
- Work::~Work()
- {
- delete current;
- }
-
- void ForenoonState::writeprogram(Work* w)
- {
- if (w->getHour() < 12)
- {
- cout << "当前时间:" << w->getHour() << "点,上午工作,精神百倍" << endl;
- }
- else
- {
- w->SetState(new NoonState());
- w->WorkProgram();
- }
- }
-
- void NoonState::writeprogram(Work* w)
- {
- if (w->getHour() < 13)
- {
- cout << "当前时间:" << w->getHour() << "点,吃午饭,睡午觉" << endl;
- }
- else
- {
- w->SetState(new AfternoonState());
- w->WorkProgram();
- }
- }
-
- void AfternoonState::writeprogram(Work* w)
- {
- if (w->getHour() < 17)
- {
- cout << "当前时间:" << w->getHour() << "点,下午状态还不错" << endl;
- }
- else
- {
- w->SetState(new EveningState());
- w->WorkProgram();
- }
- }
-
- void EveningState::writeprogram(Work* w)
- {
- if (w->getFinish())
- {
- w->SetState(new RestState());
- w->WorkProgram();
- }
- else
- {
- if (w->getHour() < 21)
- {
- cout << "当前时间:" << w->getHour() << "点,加班哦,疲惫至极 " << endl;
- }
- else
- {
- w->SetState(new SleepingState());
- w->WorkProgram();
- }
- }
- }
-
- void SleepingState::writeprogram(Work *w)
- {
- cout << "当前时间:" << w->getHour() << "点,不行了,睡着了 " << endl;
- }
-
- void RestState::writeprogram(Work *w)
- {
- cout << "当前时间:" << w->getHour() << "点,下班回家了 " << endl;
- }
-
- int main()
- {
- Work emergencyProjects;
-
- emergencyProjects.setHour(9);
- emergencyProjects.WorkProgram();
-
- emergencyProjects.setHour(10);
- emergencyProjects.WorkProgram();
-
- emergencyProjects.setHour(12);
- emergencyProjects.WorkProgram();
-
- emergencyProjects.setHour(13);
- emergencyProjects.WorkProgram();
-
- emergencyProjects.setHour(14);
- emergencyProjects.WorkProgram();
-
- emergencyProjects.setHour(17);
- emergencyProjects.WorkProgram();
-
- emergencyProjects.setFinish(false);
-
- emergencyProjects.setHour(19);
- emergencyProjects.WorkProgram();
-
- emergencyProjects.setHour(22);
- emergencyProjects.WorkProgram();
-
- system("pause");
- return 0;
- }

运行后截图:
可以看到,在客户端代码中,我们只需要调用Context类中方法即可,并不需要手动去改变状态,每执行一次方法就可以自动改变对象的状态,进而可以产生不同的行为,这就是状态模式。
- 通过把各种状态判断逻辑分布到State的子类中,减少相互之间的依赖
在状态模式中,环境(Context)中不必出现大量的条件判断语句。环境(Context)实例所呈现的状态变得更加清晰、容易理解,提高代码的可维护性。
- 如果不是有状态模式,一个对象需要在不同状态执行不同方法或者拥有不同特性的话,你可能需要在大量的 switch...case 或者 if...else 语句来根据不同状态执行不同方法,代码看起来就很复杂了
遵循设计原则
- 每一个状态都是一个子类,符合单一职责原则,且当需要增加一个状态时,也是可以增加一个子类,需要修改一个状态时,也是修改一个子类即可。
- 所有的状态都是一个子类,如果修改状态,只需要修改这个状态的子类即可,符合单一职责原则。且当需要增加一个状态时,也增加一个子类即可;需要修改一个状态时,也是修改一个子类即可。
封装性好
- 状态的变换放置在类的内部实现,外界调用不知道内部的状态改变,只要调用其方法即可。
- 由于所有的状态都是一个类,有的对象可能会有非常多的状态。随着状态的增加,系统类和对象个数也会增加。这个时候就使用状态模式就会导致类特别多,结构和实现会比较复杂,且不利于维护。如果使用不当将导致程序结构和代码的混乱。所以说,在行为受状态约束的时候使用状态模式,而且状态不超过 5 个。
- 状态模式对”开闭原则”的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态,而且修改某个状态类的行为也需修改对应类的源代码。
- 当一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为时,就可以考虑使用状态模式。
- 需要编写大量的条件分支语句来决定一个操作的行为,而且这些条件恰好表示对象的一种状态。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。