行为型模式之Status模式

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

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

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


[cpp]  view plain copy
  1. class Status {  
  2. public:  
  3.      virtual void Report() = 0;  
  4. };  
  5. class RequirementSts : public Status {  
  6. public:  
  7.      virtual void Report() {};  
  8. };  
  9. class DesignSts : public Status {  
  10. public:  
  11.      virtual void Report() {};  
  12. };  
  13. class CodingSts : public Status {  
  14. public:  
  15.      virtual void Report() {};  
  16. };  
  17. class TestingSts : public Status {  
  18. public:  
  19.      virtual void Report() {};  
  20. };  
  21. class Context {  
  22. public:  
  23.      Context(Status* sts) {  
  24.           mSts = sts;  
  25.      }  
  26.      void SetStatus(Status* sts) {  
  27.           mSts = sts;  
  28.      }  
  29.      void Report() {  
  30.           mSts->Report();  
  31.      }  
  32. private:  
  33.      Status* mSts;  
  34. };  

Client可以这样去使用:
[cpp]  view plain copy
  1. Status* require = new RequirementSts();  
  2. Context* cntxt = new Context(require);  
  3. cntxt ->Report();     // requirement report                                
  4. Status* design = new DesignSts();  
  5. Context* cntxt = new Context(design);  
  6. cntxt ->Report();     // design report  
  7. ......  

可以看出当Context类的状态发生变化时,对应的行为也会自动变化。当然我们还能更进一步,可以把状态变化的流程也封装到Context类中,首先Context类需要包含四种状态的对象,也就是在构造函数参数中需要传递一个状态组,然后把状态切换的流程封装到NextStatus方法,Client可以通过调用NextStatus方法自动切换状态和行为,代码如下:
[cpp]  view plain copy
  1. class Context {  
  2. public:  
  3.      Context(Status** sts, int stsCount) {  
  4.           mSts = sts;  
  5.           mCount = stsCount;  
  6.           mIndex = 0;  
  7.      }  
  8.      void NextStatus() {  
  9.           mIndex++;  
  10.           if (mIndex >= mCount) {  
  11.                mIndex = 0;  
  12.           }  
  13.      }  
  14.      void Report() {  
  15.           mSts[mIndex]->Report();  
  16.      }  
  17. private:  
  18.      Status** mSts;  
  19.      int mCount;  
  20.      int mIndex;  
  21. };  
Client的调用:
[cpp]  view plain copy
  1. Status* sts[4];  
  2. sts[0] = new RequirementSts();  
  3. sts[1] = new DesignSts();  
  4. sts[2] = new CodingSts();  
  5. sts[3] = new TestingSts();  
  6. Context* cntxt = new Context(sts);  
  7. cntxt ->Report();     // requirement report  
  8. cntxt->NextStatus();  
  9. cntxt ->Report();     // design report  
  10. cntxt->NextStatus();  
  11. cntxt ->Report();     // coding report  
  12. cntxt->NextStatus();  
  13. cntxt ->Report();     // testing report  

应用
当需要涉及多状态切换以及相应行为转换的问题时都可以考虑使用Status模式,它可以让代码逻辑更清晰,耦合更少,便于扩展。但是它也有一个缺点,就是由于需要把所有状态都封装成单独的类,会使系统模块增加很多类,所以这里需要在状态逻辑切换复杂度和类膨胀之间权衡一下。当然,总的来说Status模式还是一种很常见常用,比较受欢迎的模式之一.
转载请标明出处:缪买网 http://www.miumai.com/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值