最新公告
  • 欢迎您光临网站无忧模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 设计模式 - State 状态模式

    正文概述 掘金(yufeng-ltx)   2021-08-10   577

    State(状态模式)

    State(状态模式)属于行为型模式。

    意图:允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。

    简单来说,就是将 “一个大 class + 一堆 if else” 替换为 “一堆小 class”。一堆小 class 就是一堆状态,用一堆状态代替 if else 会更好拓展与维护。

    举例子

    如果看不懂上面的意图介绍,没有关系,设计模式需要在日常工作里用起来,结合例子可以加深你的理解,下面我准备了三个例子,让你体会什么场景下会用到这种设计模式。

    团队接口人

    团队是由很多同学组成的,但有一位接口人 TL,这位 TL 可能一会儿和产品经理谈需求,一会儿和其他 TL 谈规划,一会儿和 HR 谈人事,总之要做很多事情,很显然一个人是忙不过来的。TL 通过将任务分发给团队中每个同学,而不让他们直接和产品经理、其他 TL、HR 接触,那么这位 TL 的办事效率就会相当高,因为每个同学只负责一块具体的业务,而 TL 在不同时刻叫上不同的同学,让他们出面解决他们负责的专业领域问题,那么在外面看,这位 TL 团队能力很广,在内看,每个人负责的事情也比较单一。

    台灯按钮

    我们经常会看到只有一个按钮的台灯,但是可以通过按钮调节亮度,大概是如下一个循环 “关 -> 弱光 -> 亮 -> 强光 -> 关”,那么每次按按钮后,要跳转到什么状态,其实和当前状态有关。我们可以用 if else 解决这个问题,也可以用状态模式解决。

    用状态模式解决,就是将这四个状态封装为四个类,每个类都执行按下按钮后要跳转到的状态,这样未来新增一种模式,只要改变部分类即可。

    数据库连接器

    在数据库连接前后,这个连接器的状态显然非常不同,我们如果仅用一个类描述数据库连接器,则内部免不了写大量分支语句进行状态判断。那么此时有更好的方案吗?状态模式告诉我们,可以创建多个不同状态类,比如连接前、连接中、连接后三种状态类,在不同时刻内部会替换为不同的子类,它们都继承同样的父类,所以外面看上去不需要感知内部的状态变化,内部又可以进行状态拆分,进行更好的维护。

    意图解释

    意图:允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。

    重点在 “内部状态” 的理解,也就是状态改变是由对象内部触发的,而不是外部,所以 外部根本无需关心对象是否用了状态模式,拿数据库连接器的例子来说,不管这个类是用 if else 堆砌的,还是用状态模式做的,都完全不妨碍它对外提供的稳定 API(接口问题),所以状态模式实质上是一种内聚的设计模式。

    结构图

    设计模式 - State 状态模式

    • State: 状态接口,类比为台灯状态。
    • ConcreteState: 具体状态,都继承于 State,类比为台灯的强光、弱光状态。

    代码例子

    下面例子使用 typescript 编写。

    // 定义状态接口
    interface State {
      // 模拟台灯点亮
      show: () => string
    }
    
    class Light1 implements State {
      constructor(context: Context) {
        this.context = context
      }
    
      show() {
        return '关灯'
      }
    
      // 按下按钮
      public click() {
        this.context.setState(new Light2(this.context))
      }
    }
    
    class Light2 implements State {
      constructor(context: Context) {
        this.context = context
      }
    
      show() {
        return '弱光'
      }
    
      // 按下按钮
      public click() {
        this.context.setState(new Light3(this.context))
      }
    }
    
    class Light3 implements State {
      constructor(context: Context) {
        this.context = context
      }
    
      show() {
        return '亮'
      }
    
      // 按下按钮
      public click() {
        this.context.setState(new Light4(this.context))
      }
    }
    
    class Light4 implements State {
      constructor(context: Context) {
        this.context = context
      }
    
      show() {
        return '强光'
      }
    
      // 按下按钮
      public click() {
        this.context.setState(new Light1(this.context))
      }
    }
    
    // 台灯
    public class Lamp {
      // 当前状态
      private currentState = new Light1(this)
    
      protected setState(state: State) {
        this.currentState = state
      }
    
      // 按下按钮
      public click() {
        this.getState().click()
      }
    }
    
    const lamp = new Lamp() // 关闭
    lamp.click() // 弱光
    lamp.click() // 亮
    lamp.click() // 强光
    lamp.click() // 关闭
    复制代码
    

    其实有很多种方式来实现,不必拘泥于形式,大体上只要保证由多个类实现不同状态,每个类实现到下一个状态切换就好了。

    弊端

    该用 if else 的时候还是要用,不要但凡遇到 if else 就使用状态模式,那样就是书读傻了。一定要判断,是否各状态间差异很大,且使用状态模式后维护性比 if else 更好,才应该用状态模式。

    总结

    在合适场景下,状态模式可以使代码更符合开闭原则,每个类独立维护时,逻辑也更精简、聚焦,更易维护。


    下载网 » 设计模式 - State 状态模式

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元