js设计模式【详解】—— 状态模式

简介: js设计模式【详解】—— 状态模式

状态模式的定义

状态模式:当一个对象的内部状态发生改变时,会导致其行为的改变,这看起来像是改变了对象。

类型:对象行为型模式

用途:解决系统中复杂对象的状态转换以及不同状态下行为的封装问题

使用场景:

  1. 一个由一个或多个动态变化的属性导致发生不同行为的对象,在与外部事件产生互动时,其内部状态就会改变,从而使得系统的行为也随之发生变化,那么这个对象,就是有状态的对象
  2. 代码中包含大量与对象状态有关的条件语句,像是if else或switch case语句,且这些条件执行与否依赖于该对象的状态。

优点:

  1. 一个状态状态对应行为,封装在一个类里,更直观清晰,增改方便
  2. 状态与状态间,行为与行为间彼此独立互不干扰
  3. 避免事物对象本身不断膨胀,条件判断语句过多
  4. 每次执行动作不用走很多不必要的判断语句,用哪个拿哪个

缺点:

  1. 需要将事物的不同状态以及对应的行为拆分出来,有时候会无法避免的拆分的很细,有的时候涉及业务逻辑,一个动作拆分出对应的两个状态,动作就拆不明白了,过度设计
  2. 必然会增加事物类和动作类的个数,有时候动作类再根据单一原则,按照功能拆成几个类,会反而使得代码混乱,可读性降低

状态模式的一个模型——有限状态机 Finite-state machine

日常开发中很多具有多种状态的对象,都可以用有限状态机模型来模拟,一般都具有以下特点:

  1. 事物拥有多种状态,任一时间只会处于一种状态不会处于多种状态;
  2. 动作可以改变事物状态,一个动作可以通过条件判断,改变事物到不同的状态,但是不能同时指向多个状态,一个时间,就一个状态
  3. 状态总数是有限的;

github上有一个有限状态机的函数库javascript-state-machine,可以了解一下

https://github.com/jakesgordon/javascript-state-machine

演示范例1 —— 状态模式实现对话框的显示和隐藏

var Dialog = function(){
  var _state = null;
 
  this.setState = function(state){
    _state = state;
  }
  this.getState = function(){
    return _state;
  }
}
 
var ShowState = function(){
  this.doAction = function(dialog){
    console.log("对Dialog设置显示状态:");
    dialog.setState(this);
  }
  this.toString = function(){
    console.log("显示中......");
  }
}
 
var HideState = function(){
  this.doAction = function(dialog){
    console.log("对Dialog设置隐藏状态:");
    dialog.setState(this);
  }
  this.toString = function(){
    console.log("已隐藏......");
  }
}
 
var dialog = new Dialog();
 
var showState = new ShowState();
var hideState = new HideState();
 
showState.doAction(dialog);
//对Dialog设置显示状态:
dialog.getState().toString();
//显示中......
hideState.doAction(dialog);
//对Dialog设置隐藏状态
dialog.getState().toString();
//已隐藏......

例子里Dialog对象有两种状态,显示和隐藏,我把两种状态提取出来,使得状态的管理更加灵活。在这个例子里面Dialog称之为环境类,环境类又称为上下文类,他拥有多种状态。环境类内部需要维护一个state对象用来定义当前状态。HideState,ShowState称之为状态类,对应环境类的一个具体状态,toString称之为状态类的行为,每一个状态类的行为都有所不同。

演示范例2 —— 状态模式实现角色扮演游戏(如魂斗罗)

class Contra {
  constructor () {
    //存储当前待执行的动作 们
    this._currentstate = {};
  }
  //添加动作
  changeState (){
    //清空当前的动作集合
    this._currentstate = {};
    //遍历添加动作
    Object.keys(arguments).forEach(
      (i) => this._currentstate[arguments[i]] = true
    )
    return this;
  }
  //执行动作
  contraGo (){
    //当前动作集合中的动作依次执行
    Object.keys(this._currentstate).forEach(
      (k) => Actions[k] && Actions[k].apply(this)
    )
    return this;
  }
};
 
const Actions = {
  up : function(){
    //向上跳
    console.log('up');
  },
  down : function(){
    //趴下
    console.log('down');
  },
  forward : function(){
    //向前跑
    console.log('forward');
  },
  backward : function(){
    //往老家跑
    console.log('backward');
  },
  shoot : function(){
    //开枪吧
    console.log('shoot');
  },
};
var littlered = new Contra();
littlered.changeState('shoot','up').contraGo();

控制台会输出: shoot up


状态模式,将条件判断的结果转化为状态对象内部的状态(代码中的up,down,backward,forward),内部状态通常作为状态对象内部的私有变量(this._currentState),然后提供一个能够调用状态对象内部状态的接口方法对象(changeState,contraGo),这样对状态的改变,对状态方法的调用的修改和增加也会很容易,方便了对状态对象中内部状态的管理。


同时,状态模式将每一个条件分支放入一个独立的类中,也就是代码中的Actions。这使得你可以根据对象自身的情况将对象的状态(动作——up,down,backward,forward)作为一个对象(Actions.up,Actions.down这样),这一对象可以不依赖于其他对象而独立变化(一个行为一个动作,互不干扰)。


可以看出,状态模式就是一种适合多种状态场景下的设计模式,改写之后代码更加清晰,提高代码的维护性和扩展性,不用再牵一发动全身

演示范例3 —— 状态模式实现红绿灯

var trafficLight = (function () {
  var currentLight = null;
  return {
    change: function (light) {
      currentLight = light;
      currentLight.go();
    }
  }
})();
 
function RedLight() { }
RedLight.prototype.go = function () {
  console.log("this is red light");
}
function GreenLight() { }
GreenLight.prototype.go = function () {
  console.log("this is green light");
}
function YellowLight() { }
YellowLight.prototype.go = function () {
  console.log("this is yellow light");
}
 
trafficLight.change(new RedLight());
trafficLight.change(new YellowLight());

trafficLight是一个红绿灯的实例,传入一个构造函数,对象暴露change方法改变内部状态,也就是灯的颜色,change接收的同样是一个状态的对象,调用对象的方法触发响应的动作,这里的动作都叫go,不同颜色的灯对象有着不同的go的实现。


通过传入灯对象到change方法中,从而改变红绿灯的状态,触发其相应的处理程序,这就是一个典型的状态模式的应用。


更多设计模式详见——js设计模式【详解】总目录

https://blog.csdn.net/weixin_41192489/article/details/116154815

目录
相关文章
|
1月前
|
设计模式 JavaScript 前端开发
JavaScript设计模式--访问者模式
【10月更文挑战第1天】
31 3
|
2月前
|
设计模式 Java 测试技术
Java设计模式-状态模式(18)
Java设计模式-状态模式(18)
|
3月前
|
设计模式 JavaScript 前端开发
从工厂到单例再到策略:Vue.js高效应用JavaScript设计模式
【8月更文挑战第30天】在现代Web开发中,结合使用JavaScript设计模式与框架如Vue.js能显著提升代码质量和项目的可维护性。本文探讨了常见JavaScript设计模式及其在Vue.js中的应用。通过具体示例介绍了工厂模式、单例模式和策略模式的应用场景及其实现方法。例如,工厂模式通过`NavFactory`根据用户角色动态创建不同的导航栏组件;单例模式则通过全局事件总线`eventBus`实现跨组件通信;策略模式用于处理不同的表单验证规则。这些设计模式的应用不仅提高了代码的复用性和灵活性,还增强了Vue应用的整体质量。
50 1
|
3月前
|
设计模式 网络协议 Java
【十五】设计模式~~~行为型模式~~~状态模式(Java)
文章详细介绍了状态模式(State Pattern),这是一种对象行为型模式,用于处理对象在其内部状态改变时的行为变化。文中通过案例分析,如银行账户状态管理和屏幕放大镜工具,展示了状态模式的应用场景和设计方法。文章阐述了状态模式的动机、定义、结构、优点、缺点以及适用情况,并提供了Java代码实现和测试结果。状态模式通过将对象的状态和行为封装在独立的状态类中,提高了系统的可扩展性和可维护性。
【十五】设计模式~~~行为型模式~~~状态模式(Java)
|
3月前
|
设计模式 JavaScript 前端开发
小白请看 JS大项目宝典:设计模式 教你如何追到心仪的女神
小白请看 JS大项目宝典:设计模式 教你如何追到心仪的女神
|
4月前
|
设计模式 JavaScript
js设计模式【详解】—— 桥接模式
js设计模式【详解】—— 桥接模式
68 6
|
4月前
|
设计模式 JavaScript 前端开发
JavaScript进阶 - JavaScript设计模式
【7月更文挑战第7天】在软件工程中,设计模式是解决常见问题的标准解决方案。JavaScript中的工厂模式用于对象创建,但过度使用可能导致抽象过度和缺乏灵活性。单例模式确保唯一实例,但应注意避免全局状态和过度使用。观察者模式实现了一对多依赖,需警惕性能影响和循环依赖。通过理解模式的优缺点,能提升代码质量。例如,工厂模式通过`createShape`函数动态创建对象;单例模式用闭包保证唯一实例;观察者模式让主题对象通知多个观察者。设计模式的恰当运用能增强代码可维护性。
81 0
|
4月前
|
设计模式 缓存 JavaScript
js设计模式实例
【7月更文挑战第2天】JavaScript设计模式包含工厂、单例、建造者、抽象工厂和代理模式等,它们是最佳实践和可重用模板,解决创建、职责分配和通信等问题。例如,工厂模式封装对象创建,单例确保全局唯一实例,建造者模式用于复杂对象构建,抽象工厂创建相关对象集合,而代理模式则控制对象访问。这些模式提升代码质量、可读性和灵活性,是高效开发的关键。
37 0
|
15天前
|
设计模式 安全 Java
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
|
2月前
|
设计模式 数据库连接 PHP
PHP中的设计模式:提升代码的可维护性与扩展性在软件开发过程中,设计模式是开发者们经常用到的工具之一。它们提供了经过验证的解决方案,可以帮助我们解决常见的软件设计问题。本文将介绍PHP中常用的设计模式,以及如何利用这些模式来提高代码的可维护性和扩展性。我们将从基础的设计模式入手,逐步深入到更复杂的应用场景。通过实际案例分析,读者可以更好地理解如何在PHP开发中应用这些设计模式,从而写出更加高效、灵活和易于维护的代码。
本文探讨了PHP中常用的设计模式及其在实际项目中的应用。内容涵盖设计模式的基本概念、分类和具体使用场景,重点介绍了单例模式、工厂模式和观察者模式等常见模式。通过具体的代码示例,展示了如何在PHP项目中有效利用设计模式来提升代码的可维护性和扩展性。文章还讨论了设计模式的选择原则和注意事项,帮助开发者在不同情境下做出最佳决策。