JS设计模式之状态模式的用法使用方法

 更新时间:2023年08月27日 10:00:01   作者:慕仲卿  
JavaScript状态模式是一种行为型设计模式,核心是对象在其内部状态改变时改变其行为,状态模式将对象的行为封装到不同的状态类中,使得对象在不同状态下可以选择不同的行为,本文给大家详细的介绍一下状态设计模式在Js中的使用,需要的朋友可以参考下

状态模式(State Pattern)

一种行为型设计模式,核心是对象在其内部状态改变时改变其行为

状态模式将对象的行为封装到不同的状态类中,使得对象在不同状态下可以选择不同的行为。

组成

  • 环境类:环境类是拥有状态的对象,它在运行时将自身的操作委托给当前的状态对象来处理。①环境类维护一个对抽象状态类的引用,②并通过该引用来调用具体状态类的方法。

  • 抽象状态类:抽象状态类定义了一个接口③,用于封装与环境类的特定状态相关的行为。

  • 具体状态类:具体状态类实现了抽象状态类定义的接口,它具体描述了在某个状态下对象的行为④。

工作流程

  • 环境类通过持有一个抽象状态类的引用来表示当前的状态。

  • 客户端通过调用环境类的方法来触发某个操作。

  • 环境类在运行时将操作委托给当前状态对象进行处理。

  • 当对象的状态发生改变时,环境类会更新当前状态对象的引用,从而改变对象的行为。

趣例

下面的这个例子展示了一位西安老铁观看国足比赛的时候的心理状态变化过程:

abstract class State {
  constructor(public context: Context | null = null) {}
  // 这里体现出③:用于封装与环境类的特定状态相关的行为
  handle() {
    if (!this.context) {
      console.log("找不到老铁了!");
    } else {
      this.exec();
    }
  }
  next<T extends State>(NextState: new (context: Context) => T) {
    if (!this.context) {
      console.log("找不到老铁了!");
    } else {
      this.context.to(new NextState(this.context));
    }
  }
  abstract exec(): any;
}
// 具体状态类
class StateA extends State {
  // 这里体现出④:用于封装与环境类的特定状态相关的行为
  exec() {
    console.log("买票");
    this.next(StateB);
  }
}
class StateB extends State {
  exec() {
    console.log("坐车");
    this.next(StateC);
  }
}
class StateC extends State {
  exec() {
    console.log("看球");
    this.next(StateO);
  }
}
class StateO extends State {
  exec() {
    throw new Error('已经结束了');
  }
}
// 环境类
class Context {
  // 这里体现出①:环境类维护一个对抽象状态类的引用,即cts
  constructor(public cts: State | null = null) {}
  to(state: State) {
    console.log(`Transitioning to ${state.constructor.name}`);
    this.cts = state;
  }
  do() {
    // 这里体现出②:通过该引用来调用具体状态类的方法
    this.cts?.handle();
  }
}
// 使用示例
const context = new Context();
const stateA = new StateA(context);
context.to(stateA);
while(1){
  try {
    context.do();
  } catch {
    console.log('肯定输了!');
    break;
  }
}

对照例子理解

  • 状态模式:一种行为型设计模式,核心是①【对象】在其②【内部状态】③【改变】时④【改变其行为】
  • ①对象:指的是环境类对象,也就是上述代码中的context对象。

  • ②内部状态,指的是context引用的状态类实例,也就是stateA以及NextState的匿名实例。

  • ③改变:指的是context.to的调用。

  • ④行为:指的是context.do函数的执行结果。

  • 改变其行为:指的是context.cts引用不同的状态类实例的时候context.do的执行结果不同。

  • 状态模式将对象的行为封装到不同的状态类中,使得对象在不同状态下可以选择不同的行为。

    这句话理解成:

    • 本来应该在context.do中通过if else实现的功能,被封装到了不同的状态类中(StateA StateB);

    • 当context的状态改变的时候(即:context.cts引用不同的状态类实例的时候)context.do也能实现封装前相同的功能(即表现出不同的行为)。

见下面代码:

不使用状态设计模式实现上述代码功能:

class Context {
  state = 'A';
  to(state: string) {
    console.log(`Transitioning to state ${state}`);
    this.state = state;
  }
  do() {
    if(this.state === 'A'){
      console.log("买票");
      this.to('B');
    } else if (this.state === 'B') {
      console.log("坐车");
      this.to('C');
    } else if (this.state === 'C') {
      console.log("看球");
      this.to('D');
    } else if (this.state === 'D') {
      throw new Error('已经结束了');
    }
  }
}
const context = new Context();
while(1){
  try {
    context.do();
  } catch {
    console.log('肯定输了!');
    break;
  }
}

【对比】虽然这样看起来代码量好像少了一些,但是如果老铁想要在下车后去趟卫生间,使用了状态设计模式的代码只需要修改StateB的实现就可以了,而后者则必须修改Context中的do方法!

优点

  • 封装之后的状态可以独立变化,符合开闭原则

  • 状态模式提供了一种清晰的方式来组织对象的行为,并避免了使用大量的条件语句

缺点

  • 状态较多时,导致状态类的数量增加,增加系统的复杂性。

  • 对象在不同状态下的转换逻辑可能会分散在多个状态类中,使得代码难以理解和维护。

  • 如果某个状态只被一个对象使用,可以考虑使用策略模式替代状态模式。

应用

状态模式常见于需要根据对象的内部状态来改变其行为的场景,例如【订单状态的处理】、【游戏角色的状态转换】等。

它提供了一种可扩展的方式来处理状态相关的逻辑,并促进了代码的灵活性和可维护性。

generator函数可以看成原生js实现了状态设计模式。

感性记忆

同一个对象,当其内部维护的状态不同的时候,调用其上的同一个方法,可能会得到完全不同的结果。

总结

就是适用于同一个对象具有不同的状态,并且在各个状态下表现不一致的情况;这些状态之间如果是可以相互转换的,使用此设计模式就更加合适了。

到此这篇关于JS设计模式之状态模式的用法使用方法的文章就介绍到这了,更多相关JS状态模式使用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 微信小程序实现自上而下字幕滚动

    微信小程序实现自上而下字幕滚动

    这篇文章主要为大家详细介绍了微信小程序实现自上而下字幕滚动,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-07-07
  • JS中比Switch...Case更优雅的多条件判断写法

    JS中比Switch...Case更优雅的多条件判断写法

    这篇文章主要给大家介绍了关于JS中比Switch...Case更优雅的多条件判断写法,文中通过示例代码介绍的非常详细,对大家学习或者使用JS具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-09-09
  • js window.addEventListener实际案例

    js window.addEventListener实际案例

    window.addEventListener 是 JavaScript 中的一个方法,用于向指定对象添加事件监听器,下面通过本文给大家介绍js window.addEventListener的实际案例,感兴趣的朋友跟随小编一起看看吧
    2024-12-12
  • 浅谈js获取ModelAndView值的问题

    浅谈js获取ModelAndView值的问题

    下面小编就为大家分享一篇浅谈js获取ModelAndView值的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-03-03
  • javascript实现随机抽奖功能

    javascript实现随机抽奖功能

    这篇文章主要为大家详细介绍了javascript实现随机抽奖功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-12-12
  • js实现返回顶部效果

    js实现返回顶部效果

    本文主要介绍了js实现返回顶部效果的实例。具有很好的参考价值。下面跟着小编一起来看下吧
    2017-03-03
  • js实现纯前端压缩图片

    js实现纯前端压缩图片

    这篇文章主要为大家详细介绍了js实现纯前端压缩图片,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-11-11
  • function foo的原型与prototype属性解惑

    function foo的原型与prototype属性解惑

    最近在研究js,疑惑也比较多。主要是被原型这个东西给弄迷糊了。
    2010-11-11
  • JavaScript模拟实现继承的方法

    JavaScript模拟实现继承的方法

    这篇文章主要介绍了JavaScript模拟实现继承的方法,实例分析了javascript类的操作与模拟实现继承的技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-03-03
  • 使用typescript+webpack构建一个js库的示例详解

    使用typescript+webpack构建一个js库的示例详解

    这篇文章主要介绍了typescript+webpack构建一个js库,本文主要记录使用typescript配合webpack打包一个javascript library的配置过程,需要的朋友可以参考下
    2022-07-07

最新评论