• 【设计模式系列】行为型模式之Status模式


    概要
    本来不准备写Status模式,因为它跟Strategy模式简直就是对孪生兄弟,类结构类似,处理方式类似,相像的几乎没有多少好说的,后来权衡了下,毕竟这也是GOF单独提出来的一种模式,而且Status模式跟Stragegy模式的关注点多少还是有些不同的。那么Status模式到底能做什么,怎么做的呢?
    程序中经常会涉及到各种状态,每种状态下会有不同的处理逻辑,状态之间能进行切换,切换状态的同时也需要改变它们的行为,这种情况下我们的程序很容易陷入各种耦合的泥潭,Status模式可以帮助我们解决这类问题,使程序易于扩展,调理清晰。其实Strategy模式封装的是算法间的切换,而Status模式做的则是状态间的切换,关注点不同,但思路则是一样的。Strategy模式可以参考下文:
    【设计模式系列】行为型模式之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模式还是一种很常见常用,比较受欢迎的模式之一。
  • 相关阅读:
    解决UITableView中Cell重用机制导致内容出错的方法总结
    Hdu 1052 Tian Ji -- The Horse Racing
    Hdu 1009 FatMouse' Trade
    hdu 2037 今年暑假不AC
    hdu 1559 最大子矩阵
    hdu 1004 Let the Balloon Rise
    Hdu 1214 圆桌会议
    Hdu 1081 To The Max
    Hdu 2845 Beans
    Hdu 2955 Robberies 0/1背包
  • 原文地址:https://www.cnblogs.com/secbook/p/2655099.html
Copyright © 2020-2023  润新知