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

以下是详细的攻略:

学习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读取本地文件的实例

    下面是详细的讲解和示例说明。 什么是读取本地文件的实例? 在网页中,我们有时需要读取本地的文件,比如图片、音频、视频等等。而JavaScript是不允许直接访问本地文件系统的,因为这会给用户的计算机带来安全隐患。但是,如果我们得到了用户选择的文件,那么我们就可以通过操作这个文件对象来读取它的内容。 如何读取本地文件? 前提条件:用户选择了文件 我们可以通过以…

    JavaScript 2023年5月27日
    00
  • 详解JavaScript中Math内置对象基本方法的使用

    详解JavaScript中Math内置对象基本方法的使用 什么是Math对象 JavaScript中的Math对象是一个内置对象。它包含了一些常用的数学计算方法,如取绝对值、四舍五入、三角函数等。我们可以使用Math对象的方法来进行计算。 常用的Math方法 Math.ceil() 向上取整 该方法用于将一个数值向上取整,即将小数部分舍入为最接近的整数。 l…

    JavaScript 2023年5月28日
    00
  • JavaScript实现简单钟表时钟

    下面我将为你详细讲解如何使用JavaScript实现简单的钟表计时功能。 准备工作 首先,我们需要一个HTML页面作为基础。可以先创建一个空的HTML文件,然后在文件中添加以下代码: <!DOCTYPE html> <html> <head> <title>JavaScript时钟</title> …

    JavaScript 2023年5月27日
    00
  • Jquery 快速构建可拖曳的购物车DragDrop

    下面我将介绍如何使用JQuery 快速构建可拖曳的购物车DragDrop,包括下面的内容: 安装和导入JQuery脚本文件 构建基础的HTML结构 实现拖拽操作以及购物车的添加和删除 步骤一:安装和导入JQuery脚本文件 首先,你需要下载JQuery脚本文件。你可以在官方网站下载JQuery的最新版本,也可以使用CDN服务,比如: <script s…

    JavaScript 2023年6月10日
    00
  • 详解如何在JavaScript中使用装饰器

    下面我会详细介绍如何在JavaScript中使用装饰器,以及两条相关的示例说明。 什么是装饰器? 装饰器是一种特殊的函数,可以修改类、方法或属性的行为,并且可以在不改变它们原始代码的情况下实现这些修改。 装饰器源自于 Python 语言,最近已被加入 ECMAScript 标准中并成为 ES2017 的一部分,原生支持。 如何使用装饰器? 在 JavaScr…

    JavaScript 2023年6月11日
    00
  • javascript中对Attr(dom中属性)的操作示例讲解

    下面是 “javascript中对Attr(dom中属性)的操作示例讲解”的完整攻略。 什么是 Attr 在 DOM 中,每一个元素都有一系列属性(Attributes)和值(Value)。比如,元素的 id 属性、class 属性等都是属性。在 JavaScript 中,对于这些属性的操作都可以通过 Attr 来完成。 Attr 的操作 获取属性值 获取 …

    JavaScript 2023年6月10日
    00
  • JS基于HTML5的canvas标签实现炫目的色相球动画效果实例

    让我来为你讲解“JS基于HTML5的canvas标签实现炫目的色相球动画效果实例”的完整攻略。 1.什么是HTML5的canvas标签? HTML5的canvas标签是一种新的HTML标签,它提供了一种使用JavaScript和HTML5绘制图像的方法,并且支持多种绘制和渲染效果。Canvas标签用于在Web页面上绘制图形,如:线条、矩形、圆形、文本等。 2…

    JavaScript 2023年6月10日
    00
  • uniapp实现横屏签字版

    实现横屏签字版可以利用uniapp中的canvas以及第三方的canvas插件实现。 步骤一:安装canvas插件 在uniapp中使用canvas需要下载并安装canvas插件,下载地址为:https://ext.dcloud.net.cn/plugin?id=127 下载完成后,在uniapp项目的根目录下,打开cmd或者终端并输入如下命令: npm i…

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