[Design Pattern] Memento Pattern

// memento.js

import { TodoList } from "./classes.js";

export const TodoHistory = {
  history: [],
  push(state) {
    if (state) {
      // always push a new Set to avoid reference issues
      this.history.push(new Set([...state]));
    }
  },
  pop() {
    if (this.history.length > 1) {
      this.history.pop();
      return this.history.pop();
    }
  },
};

// Push new state into history when the list changes
const todoList = TodoList.getInstance();
todoList.addObserver(() => {
  TodoHistory.push(todoList.items);
});

We store the whole list into history array, when store the list, we need to save the copy to avoid reference issue.

 

Observer mixin:

export const observerMixin = {
  observers: new Set(),
  addObserver(obs) {
    this.observers.add(obs);
  },
  removeObserver(obs) {
    this.observers.delete(obs);
  },
  notify() {
    this.observers.forEach((obs) => obs());
  },
};

 

TodoList:

import { observerMixin } from "./mixin.js";

export class TodoItem {
  constructor(text) {
    this.text = text;
  }

  equals(other) {
    return this.text === other.text;
  }
}

class TodoList {
  #data = new Set();

  get items() {
    return this.#data;
  }

  /**
   * Singleton instance
   */
  static instance = null;
  static {
    this.instance = new TodoList();
  }
  static getInstance() {
    return this.instance;
  }

  constructor() {
    if (TodoList.instance) {
      throw new Error("Use TodoList.getInstance() to access the list");
    }
  }

  // behavior
  add(item) {
    const array = Array.from(this.#data);
    const todoExists = array.filter((t) => t.equals(item)).length > 0;
    if (!todoExists) {
      this.#data.add(item);
      this.notify();
    }
  }

  delete(text) {
    const array = Array.from(this.#data);
    const todoToDelete = array.filter((t) => t.text === text)[0];
    if (todoToDelete) {
      this.#data.delete(todoToDelete);
      this.notify();
    }
  }

  find(text) {
    const array = Array.from(this.#data);
    return array.find((t) => t.text === text);
  }

  replaceList(list) {
    this.#data = list;
    this.notify();
  }
}

/**Mixin */
Object.assign(TodoList.prototype, observerMixin);

export { TodoList };

 

posted @ 2024-08-19 14:45  Zhentiw  阅读(4)  评论(0编辑  收藏  举报