美文网首页
设计模式之状态模式

设计模式之状态模式

作者: 回调的幸福时光 | 来源:发表于2019-06-14 18:06 被阅读0次

一、基础介绍

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

  • 将状态封装成独立的类,并将请求委托给当前状态对象。
  • 对象具有状态变化
  • 不同的状态,对应不同的行为。
  • 状态有共同的行为方法, Context 会将请求委托给状态对象的这些方法,但是行为方法的内部实现是不同的。
状态模式 UML 类图

二、例子讲解

以 promise 为例,我们知道 promise 是对异步操作的封装,内部有 3 种状态,每种状态对应不同的行为。

以下的代码采用状态模式实现了简单版的 promise 。
注意 then 方法并未提供完整功能,没有继续返回 promise ,所以无法链式调用。

思考步骤:

  • 通常 Promise 使用关键字 new 调用,所以可以用构造函数/类来模拟。
  • 根据 Promise/A+ 规范,Promise 需要一个 executor , executor 是一个函数,有两个参数,分别是 resolvereject
  • 构造函数需要做的事情
  • then 方法参数中的回调处理不是立刻调用,而是等异步操作完成之后才会执行
  • 状态变化不可逆
//  有限状态机(Finite State Machine)
const FSM = {
  pending: {
    name: 'pending',
    done() {
      this.state = FSM.pending;
      console.log('pending 中...');
    }
  },
  resolved: {
    name: 'resolved',
    done() {
      if (this.state.name !== 'pending') return;
      this.state = FSM.resolved;
      console.log('状态更改为 resolved');
      // 调用 onResolve
      this.onResolve();
    }
  },
  rejected: {
    name: 'rejected',
    done() {
      if (this.state.name !== 'pending') return;
      this.state = FSM.rejected;
      console.log('状态更改为 rejected');
      // 调用 onReject
      this.onReject();
    }
  }
}

class myPromise {
  constructor(executor) {
    // 初始化状态为 pendding
    this.state = FSM.pending;
    FSM.pending.done.call(this);
    
    // 异步操作回调函数初始化
    this.onResolve = Function.prototype;
    this.onReject= Function.prototype;
    
    // 执行 executor
    executor(() => {
      FSM.resolved.done.call(this);
    },() => {
      FSM.rejected.done.call(this);
    })
  }

  then(onResolve, onReject) {
    // 校验 onResolve
    if (onResolve  && typeof onResolve !== 'function') {
      throw new Error("出错啦~");
    }
    
    // 校验 onReject 
    if (onReject && typeof onReject !== 'function') {
      throw new Error("出错啦~");
    }

    this.onResolve = typeof onResolve === 'function' ? onResolve : () => {};
    this.onReject = typeof onReject=== 'function' ? onReject : () => { throw new Error("出错啦~");};
  }
}

测试代码:

 // 测试代码
function ajax(type=true) {
  const promise = new myPromise((resolve, reject) => {
    setTimeout(() => {
      if (type) {
        resolve();
      } else {
        reject();
      }
    }, 1000);
  });
  return promise;
}
const response_1 = ajax();
response_1.then(()=>{
    console.log('response_1 请求成功后的处理');
},()=>{
    console.log('response_1 请求失败后的处理');
});

const response_2 = ajax(false);
response_2.then(()=>{
    console.log('response_2 请求成功后的处理');
},()=>{
    console.log('response_2 请求失败后的处理');
});
测试代码运行结果

状态变更不可逆的处理

 if (this.state.name !== 'pending') return;
状态变更是不可逆的

github 上的 JavaScript 有限状态机库

链接:jakesgordon/javascript-state-machine

三、应用场景

红绿灯、灯的开关、文件上传、游戏中任务的动作状态等。

四、优缺点

优点:

  • 避免多重条件分支语句
  • 状态模式定义了状态与行为之间的关系,并将它们封装在一个类里。易扩展,添加新的状态。
  • Context 中的请求动作状态类中封装的行为可以独立变化而互不影响

缺点:

  • 编写多个状态类。
  • 逻辑分散在状态类中。

五、状态模式中的性能优化

  1. state 对象的创建和销毁
  • 状态对象被需要时,才动态创建。
  • 开始就创建所有的状态对象。
  1. 利用享元模式,可以使个 Context 对象共享 state 对象。

六、策略模式和状态模式的关系

相同点:

  • 它们都有一个上下文、一些策略/状态类。上下文把请求委托给这些类来执行。

不同点:

  • 策略模式重点在于封装不同的算法,算法之间没有强联系,可互相替换。
  • 状态模式重点在于封装状态,行为会放在状态内部,状态之间会发生变化。

推荐阅读 设计模式之禅:策略模式VS状态模式

参考

《JavaScript 设计模式与开发实践》曾探
《JavaScript 设计模式》张容铭
Javascript设计模式系统讲解与应用

相关文章

  • Java设计模式——状态模式

    Java设计模式之状态模式 这期分享一个行为模式中的状态模式,状态模式是行为模式中的最后几个模式了。希望多多关注交...

  • 设计模式之状态设计模式

    一、浩言 人静而后安,安而能后定,定而能后慧,慧而能后悟,悟而能后得。 二、背景 开年,看了看最近网上传的《阿里巴...

  • 设计模式-状态模式

    设计模式-状态模式 设计模式 状态模式的关键是区分事物内部的状态

  • 设计模式之状态模式

    状态模式 State Intro 状态模式(State),当一个对象的内在状态改变时允许改变其行为,这个对象看起来...

  • 设计模式之状态模式

    1. 定义 允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。它是一种对象行为型模式。 2....

  • 设计模式之状态模式

    状态模式的定义 状态模式的定义如下:Allow an object to alter its behavior w...

  • 设计模式之状态模式

    在开发过程中,我们经常会遇到很多if-else的判断,有的会有很多层,当然也不是说所有的涉及到if-else判断的...

  • 设计模式之状态模式

    UML图: 没怎么完全理解,略过。

  • 设计模式之状态模式

    状态模式 汽车人接口 变形金刚的汽车型状态 变形金刚的战斗型状态 用来管理切换状态的类 客户端 状态模式的场景一个...

  • 设计模式之状态模式

    写在前面 最近写屏幕式智能家电的时候,总是需要处理各种电器状态,比如电源开启的情况下才可以进行开风机操作,风力档位...

网友评论

      本文标题:设计模式之状态模式

      本文链接:https://www.haomeiwen.com/subject/ipqpfctx.html