概要
本来不准备写Status模式,因为它跟Strategy模式简直就是对孪生兄弟,类结构类似,处理方式类似,相像的几乎没有多少好说的,后来权衡了下,毕竟这也是GOF单独提出来的一种模式,而且Status模式跟Stragegy模式的关注点多少还是有些不同的。那么Status模式到底能做什么,怎么做的呢?
程序中经常会涉及到各种状态,每种状态下会有不同的处理逻辑,状态之间能进行切换,切换状态的同时也需要改变它们的行为,这种情况下我们的程序很容易陷入各种耦合的泥潭,Status模式可以帮助我们解决这类问题,使程序易于扩展,调理清晰。其实Strategy模式封装的是算法间的切换,而Status模式做的则是状态间的切换,关注点不同,但思路则是一样的。Strategy模式可以参考下文:
本来不准备写Status模式,因为它跟Strategy模式简直就是对孪生兄弟,类结构类似,处理方式类似,相像的几乎没有多少好说的,后来权衡了下,毕竟这也是GOF单独提出来的一种模式,而且Status模式跟Stragegy模式的关注点多少还是有些不同的。那么Status模式到底能做什么,怎么做的呢?
程序中经常会涉及到各种状态,每种状态下会有不同的处理逻辑,状态之间能进行切换,切换状态的同时也需要改变它们的行为,这种情况下我们的程序很容易陷入各种耦合的泥潭,Status模式可以帮助我们解决这类问题,使程序易于扩展,调理清晰。其实Strategy模式封装的是算法间的切换,而Status模式做的则是状态间的切换,关注点不同,但思路则是一样的。Strategy模式可以参考下文:
目的
把各种状态独立封装,而把状态切换及相应处理隔离出来,使对象在改变内部状态时也改变对应状态的行为。
实例
开发一个项目管理系统,项目会经历各个阶段(可以看做各个状态),这里假设只考虑4个阶段:需求,设计,编码,测试。处于不同阶段时,系统可以输出不同的项目文档报告,比如需求阶段输出需求文档,设计时为设计文档,编码时为代码评审记录,测试时则是测试文档。看看基于Status模式会怎么考虑。
我们把各种阶段(状态)封装到不同的类,每个状态类都会有Report方法来处理不同的报告内容,而这些状态类不会去关心状态怎么切换,行为怎么改变,这些处理会封装到独立的Context类,类图和代码如下:

- class Status {
- public:
- virtual void Report() = 0;
- };
- class RequirementSts : public Status {
- public:
- virtual void Report() {};
- };
- class DesignSts : public Status {
- public:
- virtual void Report() {};
- };
- class CodingSts : public Status {
- public:
- virtual void Report() {};
- };
- class TestingSts : public Status {
- public:
- virtual void Report() {};
- };
- class Context {
- public:
- Context(Status* sts) {
- mSts = sts;
- }
- void SetStatus(Status* sts) {
- mSts = sts;
- }
- void Report() {
- mSts->Report();
- }
- private:
- Status* mSts;
- };
Client可以这样去使用:
- Status* require = new RequirementSts();
- Context* cntxt = new Context(require);
- cntxt ->Report(); // requirement report
- Status* design = new DesignSts();
- Context* cntxt = new Context(design);
- cntxt ->Report(); // design report
- ......
可以看出当Context类的状态发生变化时,对应的行为也会自动变化。当然我们还能更进一步,可以把状态变化的流程也封装到Context类中,首先Context类需要包含四种状态的对象,也就是在构造函数参数中需要传递一个状态组,然后把状态切换的流程封装到NextStatus方法,Client可以通过调用NextStatus方法自动切换状态和行为,代码如下:
- class Context {
- public:
- Context(Status** sts, int stsCount) {
- mSts = sts;
- mCount = stsCount;
- mIndex = 0;
- }
- void NextStatus() {
- mIndex++;
- if (mIndex >= mCount) {
- mIndex = 0;
- }
- }
- void Report() {
- mSts[mIndex]->Report();
- }
- private:
- Status** mSts;
- int mCount;
- int mIndex;
- };
Client的调用:
- Status* sts[4];
- sts[0] = new RequirementSts();
- sts[1] = new DesignSts();
- sts[2] = new CodingSts();
- sts[3] = new TestingSts();
- Context* cntxt = new Context(sts);
- cntxt ->Report(); // requirement report
- cntxt->NextStatus();
- cntxt ->Report(); // design report
- cntxt->NextStatus();
- cntxt ->Report(); // coding report
- cntxt->NextStatus();
- cntxt ->Report(); // testing report
应用
当需要涉及多状态切换以及相应行为转换的问题时都可以考虑使用Status模式,它可以让代码逻辑更清晰,耦合更少,便于扩展。但是它也有一个缺点,就是由于需要把所有状态都封装成单独的类,会使系统模块增加很多类,所以这里需要在状态逻辑切换复杂度和类膨胀之间权衡一下。当然,总的来说Status模式还是一种很常见常用,比较受欢迎的模式之一.
转载请标明出处:缪买网 http://www.miumai.com/