zoukankan      html  css  js  c++  java
  • 【设计模式系列】行为型模式之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模式还是一种很常见常用,比较受欢迎的模式之一。
  • 相关阅读:
    js 中基本数据类型和引用数据类型 ,,,, js中对象和函数的关系
    something
    js 的constructor属性
    js 的prototype 属性和用法,外加__proto__
    js 获取一下url里面的一些内容
    js 终于明白变量提升的概念了
    动态设置小程序的 标题
    Vue axios调用第三方接口跨域解决
    css translate的一些问题 这其实可以用在,不知道div宽高的情况,从而让其上下,左右都居中。
    用css3写一个可以无限旋转的div或者图片
  • 原文地址:https://www.cnblogs.com/secbook/p/2655099.html
Copyright © 2011-2022 走看看