博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
《JavaScript设计模式与开发实践》模式篇(13)—— 状态模式
阅读量:6582 次
发布时间:2019-06-24

本文共 3046 字,大约阅读时间需要 10 分钟。

状态模式的关键是区分事物内部的状态,事物内部状态的改变往往会带来事物的行为改变。

故事背景

我们来想象这样一个场景:有一个电灯,电灯上面只有一个开关。当电灯开着的时候,此时 按下开关,电灯会切换到关闭状态;再按一次开关,电灯又将被打开。同一个开关按钮,在不同 的状态下,表现出来的行为是不一样的

代码实现(未使用状态模式)

var Light = function(){     this.state = 'off'; // 给电灯设置初始状态 off    this.button = null;// 电灯开关按钮};Light.prototype.init = function(){    var button = document.createElement( 'button' ),    self = this;    button.innerHTML = '开关';    this.button = document.body.appendChild( button );     this.button.onclick = function(){        self.buttonWasPressed();     }};Light.prototype.buttonWasPressed = function(){     if ( this.state === 'off' ){        console.log( '开灯' );        this.state = 'on';    } else if ( this.state === 'on' ){        console.log( '关灯' );        this.state = 'off';     }};var light = new Light(); light.init();复制代码

存在的问题

假如现在电灯的状态多了一种,第一次按下打开弱光,第二次按下打开强光,第三次才是关闭电灯。以上的代码就无法满足这种电灯的情况

分析

状态模式的关键是把事物的 每种状态都封装成单独的类,跟此种状态有关的行为都被封装在这个类的内部,所以 button 被按下的的时候,只需要在上下文中,把这个请求委托给当前的状态对象即可,该状态对象会负责渲染它自身的行为。如下图所示

重构思路

  • 定义 3 个状态类
  • 改写 Light 类,使用状态对象记录当前的状态
  • 提供一个 方法来切换 light 对象的状态
/******************** 定义 3 个状态类 ************************/// OffLightState:var OffLightState = function( light ){     this.light = light;};OffLightState.prototype.buttonWasPressed = function(){     console.log( '弱光' ); // offLightState 对应的行为     this.light.setState( this.light.weakLightState );// 切换状态到 weakLightState};// WeakLightState:var WeakLightState = function( light ){     this.light = light;};WeakLightState.prototype.buttonWasPressed = function(){     console.log( '强光' ); // weakLightState 对应的行为     this.light.setState( this.light.strongLightState ); //切换状态到 strongLightState};// StrongLightState:var StrongLightState = function( light ){     this.light = light;};StrongLightState.prototype.buttonWasPressed = function(){    console.log( '关灯' ); // strongLightState 对应的行为    this.light.setState( this.light.offLightState ); // 切换状态到 offLightState};/******************* 改写 Light 类,使用状态对象记录当前的状态 ******************/var Light = function(){    this.offLightState = new OffLightState( this );     this.weakLightState = new WeakLightState( this );     this.strongLightState = new StrongLightState( this );     this.button = null;};/******************** 提供一个 方法来切换 light 对象的状态 ************************/Light.prototype.init = function(){    var button = document.createElement( 'button' ),    self = this;    this.button = document.body.appendChild( button );     this.button.innerHTML = '开关';   this.currState = this.offLightState;    this.button.onclick = function(){         self.currState.buttonWasPressed();    } };Light.prototype.setState = function( newState ){    this.currState = newState; };var light = new Light(); light.init();复制代码

改进效果

执行结果跟之前的代码一致,但是使用状态模式的好处很明显,它可以使每 一种状态和它对应的行为之间的关系局部化,这些行为被分散和封装在各自对应的状态类之中, 便于阅读和管理代码。 另外,状态之间的切换都被分布在状态类内部,这使得我们无需编写过多的 if、else 条件 分支语言来控制状态之间的转换。

总结

  • 状态模式定义了状态与行为之间的关系,并将它们封装在一个类里。通过增加新的状态 类,很容易增加新的状态和转换。
  • 避免 Context 无限膨胀,状态切换的逻辑被分布在状态类中,也去掉了 Context 中原本过 5 多的条件分支。
  • 用对象代替字符串来记录当前状态,使得状态的切换更加一目了然。
  • Context 中的请求动作和状态类中封装的行为可以非常容易地独立变化而互不影响

系列文章:

转载地址:http://pcino.baihongyu.com/

你可能感兴趣的文章
Setting up the Web Admin Tool in LDAP 6.x to communicate via SSL
查看>>
IOS开发一些常用功能
查看>>
SQL好习惯:编写支持可搜索的SQL
查看>>
Shadowbox
查看>>
【 程 序 员 】:伤不起的三十岁,你还有多远 ?
查看>>
Oracle存储过程:判断表中记录是否存在,存在则更新,不存在则插入!
查看>>
现代软件构建系统的使用 CMake简介
查看>>
Microsoft® SQL Server® 2008 Management Studio Express
查看>>
ZOJ 3604 Help Me Escape(期望DP)
查看>>
Collections.shuffle()源码分析
查看>>
hosts表的作用
查看>>
Skype 4.1 Linux 发布,支持微软帐号登录
查看>>
hexdump 1.8 发布,十六进制数据查看工具
查看>>
openldap安装
查看>>
C++ istream::peek()
查看>>
[leetcode]count and say
查看>>
flex java socket通信
查看>>
比VC的TRACE还要好的调试命令
查看>>
回忆大学到现在为止学到了什么?
查看>>
润乾报表 - 缓存问题
查看>>