状态模式通识篇
前言
状态模式也是行为型模式中的一种,顾名思义状态模式主要是基于对象有不同的状态,从而导致具有与其对应状态的行为。
场景
为了更好的理解状态模式,我们假设有这样的需要,我们有一个电灯,电灯可以在有打开、关闭、坏的三种情况。在开灯的时候,我们可以看书;在关灯的时候,我们什么也看不到;在灯坏的时候,我们不能进行任何操作。想一想你的代码会如何写呢?
// 一如既往的零散代码 获取电灯状态
let status = light.status
switch(status){
case 'on':console.log('light is on ,we can read books');
break;
case 'off':console.log('light is off ,we can not see anything');
break;
case 'error':console.log('light is error ,we can not do any operation');
break;
}
但是你想一直这样写么?这个代码是只执行一次的,为了更好的进行函数的执行,我们也许会把状态判断封装为一个函数,比如下面这样。
function lightTip(status){
case 'on':console.log('light is on ,we can read books');
break;
case 'off':console.log('light is off ,we can not see anything');
break;
case 'error':console.log('light is error ,we can not do any operation');
break;
}
// 获取状态执行操作
let status = light.status
lightTip(status)
// 其他逻辑里更改状态执行
light.status = 'off'
// 继续执行
let status = light.status
lightTip(status)
思考抽象为电灯状态
等等,当这样写下去,其实明明是很规整特殊的一个电灯对象,为什么不按照灯这个类封装一下,然后根据不同状态提供行为,同时把设置状态的部分,每个状态执行操作的部分都封装一下,方便维护也方便更加规范的切换。不妨看下下面这种写法??(图是java的,js的原理是一样的,理解就好)
// 电灯类
class light{
setState(state){
this.state = state
}
getState(){
return this.state.status
}
request(){
return this.state.handler()
}
}
// 状态类
class lightState{
constructor(){
this.status = ''
}
handler(context){
console.error('不在任何有效状态')
}
}
// 具体状态实现 启动状态
class onState extends lightState{
constructor(){
super();
this.status='on'
}
handler(){
console.log('light is on ,we can read books')
}
}
// 关闭状态实现
class offState extends lightState{
constructor(){
super();
this.status='off'
}
handler(){
console.log('light is off ,we can not see anything')
}
}
let lightDemo = new light()
lightDemo.setState(new onState())
lightDemo.request()
lightDemo.setState(new offState())
lightDemo.request()
这样设计区别之后,我们每个电灯都可以分别的管理,每个电灯的状态都继承自状态类,需要实现其必要的抽象方法以及在这个公共方法里执行需要的一些状态里的方法。
说好的玛丽呢
其实状态模式不一定要class类来具体实现,它更是一种设计思想,只要你是按照这样的思想去组织代码就可以了。
先说下基本的需求,我们按照游戏设定,给其提供不同的动作,包括眺,前进,射击,蹲下以及复合的一些操作,我们需要根据用户需要可以追加一系列的操作,追加之后可以执行,也可以随时追踪到玛丽最新的动作状态。
同样我会这短代码写到codepen上,方便我们看到最终设计之后的一个效果。
function MarryState(){
// 存储用户输入的状态
var currentState = {}
let marry = document.getElementById('marry');
// 针对每个状态 定义对应状态需要写的代码
var state = {
forward:function(){
let marginLeft = marry.style.marginLeft
marry.style.marginLeft = !marginLeft? '15px': parseInt(marginLeft)+15+'px'
},
back:function(){
let marginLeft = marry.style.marginLeft
marry.style.marginLeft = !marginLeft? '15px': parseInt(marginLeft)-15+'px'
},
jump:function(){
marry.classList.add('jump') ; setTimeout(function(){marry.classList.remove('jump')},1000)
},
}
// 每个action的部分 提供链式操作,所以每次执行完之后返回this
var action = {
changeState:function(){
var areg = arguments ;
currentState={};
if(areg.length){
for(var i=0,len=areg.length;i<len;i++){
currentState[areg[i]] = true;
}
}
return this;
},
go:function(){
for(var p in currentState){
state[p] && state[p]()
}
return this;
}
}
return {
change:action.changeState,
go:action.go
}
}
// 实例化
var marrySample = new MarryState();
// 进行事件委托
let topOpt = document.getElementById("topOpt")
topOpt.addEventListener('click',function(e){
marrySample.change(e.target.id).go()
})
// 定义一系列的状态动作
function animateActions(){
marrySample.change('jump','forward','forward','back').go().go().go().go()
}
animateActions()
小结
分析下,其实以上的代码完全可以通过switch分支实现,之所以封装一个对应状态对象的函数,并通过暴露改变状态的方法以及执行操作的方法执行对应状态的代码逻辑。
所以其真正适用的场景是: – 代码中包含了大量与状态相关的判断语句 – 对象的行为与状态强相关绑定,并随着状态的改变而改变 – 一个对象的状态并不是锁定的,而是可能会动态变化的,甚至是规律辩护,比如玛丽的跳跃射击的操作、向前跳跃的操作等。
这样的模式设计之后的优点是: – 减少了因为不同状态判断写的分支语句或者条件判断语句 – 每个状态维护在一个子类或者一个封装的方法里,便于单独维护 – 状态放到了内部,外部不知道状态的执行以及互相关系
这样的缺点: – 如果状态过多,会产生很多子类,第一种方式的缺点;这种时候其实可以采用封装到函数级别即可;
- WordPress文章版权保护:复制文字自动添加版权信息
- 替换WordPress 自带默认的 jQuery库, jQuery库页脚加载
- Enterprise Library 4 数据访问应用程序块
- 替换EnterPrise Library 4.0 缓存应用程序块的CacheManager
- Enterprise Library 4.0缓存应用程序块
- 通过.htaccess 让WordPress 的上传文件夹更安全
- asp.net 性能调较
- 零基础学习大数据,搭建Hadoop处理环境
- 为你的WordPress 博客开启两步验证功能(技术支持:谷歌)
- 为你的WordPress 博客开启两步验证功能(技术支持:谷歌)
- WordPress 注册页面显示自定义提示信息
- Windows Server 2008密码重设盘
- Dynamite动态排序库
- WordPress 顶部管理工具条添加自定义栏目
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 基于Spark Graphx实现ID-Mapping
- Nginx keepalived一主一从高可用,手把手带你一步一步配置!
- Android实现自动轮询的RecycleView
- Android自定义钟表特效
- Android MediaPlayer 音频倍速播放 调整播放速度问题
- Android 简单实现倒计时功能
- Android Canvas自定义实现时钟效果
- 虚拟机kali安装vmtools
- Android动画学习笔记之补间动画
- [- Flutter 数据&状态篇 -] setState
- flutter 自定义websocket路由的实现
- Flutter开发之路由与导航的实现
- Android BSearchEdit 搜索结果选择框的实例代码
- 使用AccessibilityService实现微信自动切换账号功能
- Android评分RationBar控件使用详解