likes
comments
collection
share

备忘录模式:把你过去的状态都存储下来,让你可以随时回到过去

作者站长头像
站长
· 阅读数 16

简介

备忘录模式(Memento Pattern)是一种行为型设计模式,它允许在不破坏对象封装性的情况下,捕获和保存对象的内部状态,并在需要时将对象恢复到先前的状态。该模式提供了一种保存对象状态的机制,使得对象可以在后续需要时恢复到之前的状态。

使用场景

备忘录模式适用于以下情况:

  • 需要记录和恢复对象的状态,而不暴露其内部实现细节。
  • 需要提供撤销功能,允许用户回退到先前的对象状态。
  • 需要保存对象的某个特定时间点的状态,并在需要时进行恢复。

结构和角色

备忘录模式包含以下角色:

  • 发起人(Originator):负责创建备忘录对象,并可以使用备忘录对象恢复其状态。
  • 备忘录(Memento):用于存储发起人对象的内部状态。
  • 负责人(Caretaker):负责保存备忘录对象,并在需要时将其提供给发起人。

示例:在Vue3中使用

假设您正在开发一个Vue3应用程序,该应用程序具有角色管理功能。您希望提供一个撤销功能,允许用户回退到之前的角色状态。我们将使用备忘录模式来实现这一功能。

1. 定义发起人(Originator)

在我们的示例中,发起人是角色管理器(RoleManager),它负责管理角色的状态。发起人的代码如下:

import { reactive, toRefs } from 'vue';

// 创建角色管理器
export function createRoleManager() {
  // 角色状态
  const state = reactive({
    roles: [],
  });

  // 添加角色
  function addRole(role) {
    state.roles.push(role);
  }

  // 保存角色状态的备忘录
  function saveState() {
    const snapshot = JSON.stringify(state.roles);
    return { snapshot };
  }

  // 恢复角色状态
  function restoreState(memento) {
    state.roles = JSON.parse(memento.snapshot);
  }

  // 导出响应式状态
  return {
    ...toRefs(state),
    addRole,
    saveState,
    restoreState,
  };
}

发起人(RoleManager)使用Vue3的响应式函数(reactive)来创建一个包含角色状态的响应式对象。它包含以下功能:

  • addRole(role): 添加角色到角色管理器中。
  • saveState(): 创建并返回当前角色状态的备忘录对象。
  • restoreState(memento): 使用备忘录对象恢复角色状态。

2. 定义备忘录(Memento)

备忘录(Memento)对象用于存储角色管理器(RoleManager)的状态快照。在我们的示例中,备忘录对象将保存角色数组的快照。

// 创建备忘录对象
export function createMemento(snapshot) {
  return {
    snapshot,
  };
}

备忘录对象(Memento)是一个简单的函数,它接收一个快照参数,并返回一个包含快照的备忘录对象。

3. 使用备忘录模式

我们现在可以在Vue组件中使用备忘录模式来实现撤销功能。以下是一个简单的Vue组件示例:

<template>
  <div>
    <h2>角色管理</h2>
    <ul>
      <li v-for="role in roles" :key="role.id">{{ role.name }}</li>
    </ul>
    <button @click="addRole">添加角色</button>
    <button @click="undo">撤销</button>
  </div>
</template>

<script>
import { createRoleManager, createMemento } from './roleManager';

export default {
  setup() {
    const roleManager = createRoleManager();

    // 添加角色
    function addRole() {
      const role = { id: Date.now(), name: '角色名称' };
      roleManager.addRole(role);
    }

    // 撤销操作
    function undo() {
      const memento = roleManager.saveState();
      roleManager.restoreState(memento);
    }

    return {
      ...roleManager,
      addRole,
      undo,
    };
  },
};
</script>

在上述示例中,我们创建了一个Vue组件来管理角色。通过调用addRole方法,我们可以向角色管理器中添加一个新角色。通过调用undo方法,我们可以撤销到之前的角色状态。

undo方法中,我们首先调用roleManager.saveState()来保存当前角色状态的备忘录对象。然后,我们再次调用roleManager.restoreState(memento),将角色状态恢复到之前的状态。

通过在Vue组件中使用备忘录模式,我们实现了撤销功能,允许用户回退到之前的角色状态。

在原生 JavaScript 项目中使用备忘录模式的实现案例:

// 发起人(Originator)
class TextEditor {
  constructor() {
    this.content = '';
  }

  type(text) {
    this.content += text;
  }

  getContent() {
    return this.content;
  }

  createMemento() {
    return new Memento(this.content);
  }

  restoreFromMemento(memento) {
    this.content = memento.getContent();
  }
}

// 备忘录(Memento)
class Memento {
  constructor(content) {
    this.content = content;
  }

  getContent() {
    return this.content;
  }
}

// 负责人(Caretaker)
class History {
  constructor() {
    this.mementos = [];
  }

  push(memento) {
    this.mementos.push(memento);
  }

  pop() {
    return this.mementos.pop();
  }
}

// 使用备忘录模式保存和恢复文本编辑器的状态
const textEditor = new TextEditor();
const history = new History();

textEditor.type('Hello, ');
history.push(textEditor.createMemento());

textEditor.type('world!');
console.log(textEditor.getContent()); // Output: Hello, world!

textEditor.restoreFromMemento(history.pop());
console.log(textEditor.getContent()); // Output: Hello,

在这个案例中,我们创建了一个简单的文本编辑器(TextEditor),它具有输入文本、获取内容、创建备忘录和从备忘录恢复的功能。我们还创建了一个历史记录(History)来保存备忘录对象。

首先,我们向文本编辑器输入文本并创建一个备忘录,然后将其压入历史记录中。然后,我们继续输入更多的文本。最后,我们通过弹出历史记录中的备忘录对象,将文本编辑器恢复到之前的状态。

通过使用备忘录模式,我们可以在不破坏文本编辑器封装性的情况下,保存和恢复其状态。这对于实现撤销/重做功能或保存应用程序的某个特定时间点的状态非常有用。

下面是一个在React中使用备忘录模式的示例:

import React, { useState } from 'react';

// 备忘录对象(Memento)
class Memento {
  constructor(content) {
    this.content = content;
  }

  getContent() {
    return this.content;
  }
}

// 角色管理器(Originator)
const RoleManager = () => {
  const [roles, setRoles] = useState([]);
  const [memento, setMemento] = useState(null);

  // 添加角色
  const addRole = () => {
    const newRole = { id: Date.now(), name: '新角色' };
    setRoles((prevRoles) => [...prevRoles, newRole]);
  };

  // 保存状态到备忘录
  const saveState = () => {
    setMemento(new Memento(roles));
  };

  // 恢复状态
  const restoreState = () => {
    if (memento) {
      setRoles(memento.getContent());
      setMemento(null);
    }
  };

  return (
    <div>
      <h2>角色管理</h2>
      <ul>
        {roles.map((role) => (
          <li key={role.id}>{role.name}</li>
        ))}
      </ul>
      <button onClick={addRole}>添加角色</button>
      <button onClick={saveState}>保存状态</button>
      <button onClick={restoreState}>恢复状态</button>
    </div>
  );
};

export default RoleManager;

在这个案例中,我们使用React函数式组件和React Hooks来管理角色的状态和备忘录。RoleManager组件中包含了一个角色列表roles和一个备忘录memento的状态。

通过点击"添加角色"按钮,我们可以向角色列表中添加新角色。通过点击"保存状态"按钮,我们可以将当前角色列表的状态保存到备忘录中。通过点击"恢复状态"按钮,我们可以将角色列表恢复到之前保存的状态。

这样,我们就实现了在React应用中使用备忘录模式来保存和恢复状态的功能。通过将状态保存到备忘录对象中,我们可以实现撤销操作或恢复到之前的状态。

结论

备忘录模式是一种非常有用的设计模式,可以在需要时保存和恢复对象的状态,实现撤销和重做功能。在本文中,我们演示了如何在Vue3的组件和setup函数中使用备忘录模式来实现撤销功能。通过将角色状态封装在备忘录对象中,我们能够保存和恢复角色管理器的状态,使用户能够回退到之前的状态。

备忘录模式的灵活性使其适用于各种场景,包括文本编辑器、游戏进度管理、撤销/重做功能等。通过将对象状态的保存和恢复功能委托给备忘录对象,我们可以更好地管理对象的状态变化,并提供更好的用户