学习JavaScript设计模式之状态模式

yizhihongxing

以下是详细的攻略:

学习JavaScript设计模式之状态模式

状态模式是什么?

状态模式是一种行为型设计模式,它允许对象在其内部状态更改时更改其行为。这个模式的主要想法是通过创建有限状态机来满足状态相关行为的需要。

状态模式的优点?

  • 优化大型、复杂代码的结构。
  • 减少了 if 语句的使用,使得代码更加简洁。
  • 更好的可扩展性,可以方便地增加、删除或修改状态,而无需更改上下文代码。
  • 状态类可以自行管理其状态,从而有助于减少上下文的复杂性。

状态模式的组成部分?

  • State(状态):定义有限状态机中的状态,每个状态都实现自己的行为。
  • Context(上下文):维护着一个 State 实例并将所有与状态相关的请求委托给当前状态。
  • ConcreteState(具体状态):实现状态定义的行为。

状态模式的实现过程?

我们将使用一个由闹钟组成的示例来说明状态模式。

  1. 首先,定义一个 State 接口或抽象类,该接口或类声明了所有具体状态类所需实现的操作:
class State {
  constructor(clock) {
    this.clock = clock;
  }

  clickMode() {
    throw new Error('This method must be overwritten!');
  }

  clickH() {
    throw new Error('This method must be overwritten!');
  }

  clickM() {
    throw new Error('This method must be overwritten!');
  }
}
  1. 然后,定义所有具体状态类都需实现的操作:
class ClockState extends State {
  clickMode() {
    this.clock.setState(new AlarmState(this.clock));
  }

  clickH() {
    throw new Error('This method must be overwritten!');
  }

  clickM() {
    throw new Error('This method must be overwritten!');
  }
}

class DisplayState extends State {
  clickMode() {
    this.clock.setState(new ClockState(this.clock));
  }

  clickH() {
    this.clock.incrementHour();
  }

  clickM() {
    this.clock.incrementMinute();
  }
}

class AlarmState extends State {
  clickMode() {
    this.clock.setState(new DisplayState(this.clock));
  }

  clickH() {
    this.clock.incrementAlarmHour();
  }

  clickM() {
    this.clock.incrementAlarmMinute();
  }
}
  1. 接着,定义上下文(闹钟)类,维护一个 State 实例并将所有与状态相关的请求委托给当前状态:
class Clock {
  constructor() {
    this.state = new DisplayState(this);
    this.hour = 0;
    this.minute = 0;
    this.alarmHour = 0;
    this.alarmMinute = 0;
  }

  setState(state) {
    this.state = state;
  }

  incrementHour() {
    this.hour++;
    console.log(`Hours: ${this.hour}`);
  }

  incrementMinute() {
    this.minute++;
    console.log(`Minutes: ${this.minute}`);
  }

  incrementAlarmHour() {
    this.alarmHour++;
    console.log(`Alarm hours: ${this.alarmHour}`);
  }

  incrementAlarmMinute() {
    this.alarmMinute++;
    console.log(`Alarm minutes: ${this.alarmMinute}`);
  }

  mode() {
    this.state.clickMode();
    console.log(`Current state: ${this.state.constructor.name}`);
  }

  h() {
    this.state.clickH();
  }

  m() {
    this.state.clickM();
  }
}
  1. 最后,使用上下文类实例来启动整个程序:
const clock = new Clock();
clock.h();
clock.m();
clock.mode();
clock.m();
clock.h();
clock.mode();
clock.mode();
clock.h();

这个示例充分展示了状态模式的能力:通过使用基类和 ConcreteState 向对象中添加新的状态并将其轻松重新配置,同时保持开放/封闭原则,即不会修改现有代码。

示例说明:

一个本地存储库示例说明了状态模式的优点。这个库有两个状态:

  1. 未初始化状态。
  2. 初始化状态。

当状态处于未初始化状态时,LocalStore 类的各种方法将不执行。当状态转换为初始化状态时,这些方法将执行,并且检查是否存在本地存储,如果它不存在,则进行初始化。

class LocalStoreUninitialized {
  constructor() {
    console.log('store is uninitialized');
  }

  init() {
    console.log('Initializing store...');
    const items = {};
    localStorage.setItem('items', JSON.stringify(items));
    this.localStore.setState(this.localStore.states.initialized);
  }

  addNew(item) {
    throw new Error('Cannot call addNew() on an uninitialized store.');
  }

  deleteItem(id) {
    throw new Error('Cannot call deleteItem() on an uninitialized store.');
  }

  getItems() {
    throw new Error('Cannot call getItems() on an uninitialized store.');
  }
}

class LocalStoreInitialized {
  constructor() {
    console.log('store is initialized');
  }

  init() {
    console.log('store already initialized');
  }

  addNew(item) {
    const items = JSON.parse(localStorage.getItem('items'));
    items[item.id] = item;
    localStorage.setItem('items', JSON.stringify(items));
    console.log(`Added new item with id: ${item.id}`);
  }

  deleteItem(id) {
    const items = JSON.parse(localStorage.getItem('items'));
    delete items[id];
    localStorage.setItem('items', JSON.stringify(items));
    console.log(`Deleted item with id: ${id}`);
  }

  getItems() {
    const items = JSON.parse(localStorage.getItem('items'));
    console.log(items);
  }
}

class LocalStore {
  constructor() {
    this.states = {
      uninitialized: new LocalStoreUninitialized(),
      initialized: new LocalStoreInitialized(),
    };
    this.setState(this.states.uninitialized);
  }

  setState(state) {
    this.state = state;
    this.state.localStore = this;
  }

  init() {
    this.state.init();
  }

  addNew(item) {
    this.state.addNew(item);
  }

  deleteItem(id) {
    this.state.deleteItem(id);
  }

  getItems() {
    this.state.getItems();
  }
}

const localStore = new LocalStore();

localStore.init();
localStore.addNew({
  id: 1,
  name: 'Item 1',
});
localStore.getItems();
localStore.addNew({
  id: 2,
  name: 'Item 2',
});
localStore.getItems();
localStore.deleteItem(1);
localStore.getItems();

在上面的示例中,我们使用了两个具体状态(初始化和未初始化),以及 LocalStore 类的上下文来管理状态。当 LocalStore 类的实例创建时,它的状态被设置为未初始化。这意味着所有 LocalStore 上的方法都将抛出错误,直到 init 方法被调用并初始化了存储。初始化之后,状态被设置为初始化,并且上下文中的所有方法都可以正常工作。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:学习JavaScript设计模式之状态模式 - Python技术站

(0)
上一篇 2023年5月28日
下一篇 2023年5月28日

相关文章

  • js中关于String对象的replace使用详解

    String对象的replace方法是JavaScript中用于替换字符串中指定字符或字符串的方法。该方法可以接受一个正则表达式或字符作为第一个参数,并将其替换成给定的字符串。以下是关于该方法的详细讲解: 基本语法 replace方法的基本语法如下: string.replace(searchValue, replaceValue); 其中,string 是…

    JavaScript 2023年5月27日
    00
  • Javascript window对象详解

    Javascript window对象详解 window对象是JavaScript中的全局对象,它代表浏览器窗口或标签页。在网页中,我们经常使用window对象来操作浏览器窗口、加载新的文档等。 获取窗口的大小和位置 要获取窗口的大小和位置,我们可以使用window.innerWidth、window.innerHeight、window.outerWidt…

    JavaScript 2023年5月27日
    00
  • jQuery拖拽 & 弹出层 介绍与示例

    下面我将详细讲解“jQuery拖拽 & 弹出层 介绍与示例”的完整攻略。本攻略包含以下四个主要部分: jQuery拖拽的介绍 jQuery拖拽的实现方法 jQuery弹出层的介绍 jQuery弹出层的实现方法 1. jQuery拖拽的介绍 jQuery拖拽是指在页面中,用鼠标来拖拽页面上的元素,实现元素的位置移动效果。jQuery拖拽非常常见,尤其是…

    JavaScript 2023年6月11日
    00
  • Asp.net中使用DapperExtensions和反射来实现一个通用搜索

    下面是关于Asp.net中使用DapperExtensions和反射来实现一个通用搜索的详细攻略。 简介 DapperExtensions是一个用于扩展Dapper ORM的库,它可以方便地进行一些高级查询操作。通常情况下,我们需要编写大量的重复代码来实现这些查询操作。而DapperExtensions就是为了解决这些问题而生的。在本篇文章中,我们将通过Da…

    JavaScript 2023年6月11日
    00
  • JavaScript代码因逗号不规范导致IE不兼容的问题

    对于JavaScript代码而言,逗号的使用是非常普遍的,用于分割数组中的项、对象中的属性等等,在这些情况下逗号一般不会产生什么问题,但如果逗号使用不规范,就可能会导致IE浏览器无法解析JavaScript代码,从而出现兼容性问题。这种兼容性问题的解决方法比较简单,只需要遵守一些规范就可以了。 下面是解决这个兼容性问题的完整攻略: 1. 避免将逗号作为语句的…

    JavaScript 2023年5月18日
    00
  • js tab效果的实现代码

    让我们来详细讲解”js tab效果的实现代码”的完整攻略。 1. 理解Tab切换效果 Tab切换效果是指点击页面上的不同标签页,页面的显示内容随之改变,以达到切换页面内容的效果。我们通过JavaScript来实现这种效果,通常包含以下几个部分: 标签栏:包含多个标签的容器 内容栏:多个不同的内容页,与标签一一对应 切换函数:用于实现标签栏的点击事件,实现标签…

    JavaScript 2023年6月10日
    00
  • javascript数组去重方法汇总

    JavaScript数组去重方法汇总 在JavaScript中,数组是一种非常重要的数据类型,经常在实际的开发中用来存储一系列数据。但是,有时候我们需要对数组进行去重操作,即只保留数组中的不重复元素。本文将介绍几种常用的JavaScript数组去重方法。 1.使用Set对象 使用ES6中新增的Set对象可以非常方便地对数组进行去重。Set对象中的所有元素都是…

    JavaScript 2023年5月27日
    00
  • Javascript前端下载后台传来的文件流代码实例

    Javascript前端下载后台传来的文件流是一个常见的 Web 开发需求,下面我将详细讲解实现它的完整攻略。 第一步:后台传递文件流 在后台开发过程中,返回文件流需要设置正确的 Content-Type 和 Content-Disposition 头部信息。下面是示例代码: from flask import send_file, make_respons…

    JavaScript 2023年5月27日
    00
合作推广
合作推广
分享本页
返回顶部