[设计模式系列]行为型模式之Status模式

来源:岁月联盟 编辑:exp 时间:2012-07-05

概要
本来不准备写Status模式,因为它跟Strategy模式简直就是对孪生兄弟,类结构类似,处理方式类似,相像的几乎没有多少好说的,后来权衡了下,毕竟这也是GOF单独提出来的一种模式,而且Status模式跟Stragegy模式的关注点多少还是有些不同的。那么Status模式到底能做什么,怎么做的呢?
程序中经常会涉及到各种状态,每种状态下会有不同的处理逻辑,状态之间能进行切换,切换状态的同时也需要改变它们的行为,这种情况下我们的程序很容易陷入各种耦合的泥潭,Status模式可以帮助我们解决这类问题,使程序易于扩展,调理清晰。其实Strategy模式封装的是算法间的切换,而Status模式做的则是状态间的切换,关注点不同,但思路则是一样的。Strategy模式可以参考下文:
【设计模式系列】行为型模式之Strategy模式

目的
把各种状态独立封装,而把状态切换及相应处理隔离出来,使对象在改变内部状态时也改变对应状态的行为。

实例
开发一个项目管理系统,项目会经历各个阶段(可以看做各个状态),这里假设只考虑4个阶段:需求,设计,编码,测试。处于不同阶段时,系统可以输出不同的项目文档报告,比如需求阶段输出需求文档,设计时为设计文档,编码时为代码评审记录,测试时则是测试文档。看看基于Status模式会怎么考虑。
我们把各种阶段(状态)封装到不同的类,每个状态类都会有Report方法来处理不同的报告内容,而这些状态类不会去关心状态怎么切换,行为怎么改变,这些处理会封装到独立的Context类,类图和代码如下:


[cpp] 
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可以这样去使用:
[cpp] 
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方法自动切换状态和行为,代码如下:
[cpp] 
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的调用:
[cpp] 
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 
作者:my_business