typescript: Memento Pattern

发布时间 2023-10-11 18:10:11作者: ®Geovin Du Dream Park™

 

/**
 * Memento Pattern 备忘录是一种行为设计模式, 允许生成对象状态的快照并在以后将其还原。
 * The Originator holds some important state that may change over time. It also
 * defines a method for saving the state inside a memento and another method for
 * restoring the state from it.
 */
class Originator {
    /**
     * For the sake of simplicity, the originator's state is stored inside a
     * single variable.
     */
    private state: string;
    /**
     * 
     * @param state 
     */
    constructor(state: string) {
        this.state = state;
        console.log(`Originator: My initial state is: ${state}`);
    
    }

    /**
     * The Originator's business logic may affect its internal state. Therefore,
     * the client should backup the state before launching methods of the
     * business logic via the save() method.
     */
    public doSomething(): void {
        console.log('Originator: I\'m doing something important.');
        this.state = this.generateRandomString(30);
        console.log(`Originator: and my state has changed to: ${this.state}`);
    }
    /**
     * 
     * @param length 
     * @returns 
     */
    private generateRandomString(length: number = 10): string {
        const charSet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';

        return Array
            .apply(null, { length })
            .map(() => charSet.charAt(Math.floor(Math.random() * charSet.length)))
            .join('');
    }

    /**
     * Saves the current state inside a memento.
     */
    public save(): Memento {
        return new ConcreteMemento(this.state);
    }

    /**
     * Restores the Originator's state from a memento object.
     */
    public restore(memento: Memento): void {
        this.state = memento.getState();
        console.log(`Originator: My state has changed to: ${this.state}`);
    }
}

/**
 * The Memento interface provides a way to retrieve the memento's metadata, such
 * as creation date or name. However, it doesn't expose the Originator's state.
 */
interface Memento {

    /**
     * 
     *  @returns
     */
    getState(): string;

    /**
     * 
     *  @returns
     */
    getName(): string;

    /**
     * 
     *  @returns
     */
    getDate(): string;
}

/**
 * The Concrete Memento contains the infrastructure for storing the Originator's
 * state.
 */
class ConcreteMemento implements Memento {
    private state: string;

    private date: string;
    /**
     * 
     * @param state 
     */
    constructor(state: string) {
        this.state = state;
        this.date = new Date().toISOString().slice(0, 19).replace('T', ' ');
    }

    /**
     * The Originator uses this method when restoring its state.
     *  @returns
     */
    public getState(): string {
        return this.state;
    }

    /**
     * The rest of the methods are used by the Caretaker to display metadata.
     *  @returns
     */
    public getName(): string {
        return `${this.date} / (${this.state.substr(0, 9)}...)`;
    }

    /**
     * 
     * @returns 
     */
    public getDate(): string {
        return this.date;
    }
}

/**
 * The Caretaker doesn't depend on the Concrete Memento class. Therefore, it
 * doesn't have access to the originator's state, stored inside the memento. It
 * works with all mementos via the base Memento interface.
 */
class Caretaker {

    private mementos: Memento[] = [];

    private originator: Originator;
    /**
     * 
     * @param originator 
     */
    constructor(originator: Originator) {
        this.originator = originator;
    }
    /**
     * 
     */
    public backup(): void {
        console.log('\nCaretaker: Saving Originator\'s state...');
        this.mementos.push(this.originator.save());
    }
    /**
     * 
     * @returns 
     */
    public undo(): void {


        if (!this.mementos.length) {
            return;
        }
        const memento = this.mementos.pop();

        console.log(`Caretaker: Restoring state to: ${memento.getName()}`);
        this.originator.restore(memento);
    }
    /**
     * 
     *  @returns
     */
    public showHistory(): string { //void
        let getstr="";
        console.log('Caretaker: Here\'s the list of mementos:');
        for (const memento of this.mementos) {
            console.log(memento.getName());
            getstr=getstr+memento.getName()+","+memento.getState();
           // return memento.getName();
        }

        return getstr;
    }
}


let pubMemento1="";
let pubMemento2="";
let pubMemento3="Geovin Du";
let pubMemento4="geovindu";
/**
 * Client code.
 */
const originator = new Originator('Super-duper-super-puper-super.');
const caretaker = new Caretaker(originator);

caretaker.backup();
originator.doSomething();

caretaker.backup();
originator.doSomething();

caretaker.backup();
originator.doSomething();

console.log('');
pubMemento1=pubMemento1+caretaker.showHistory();

console.log('\nClient: Now, let\'s rollback!\n');
caretaker.undo();

console.log('\nClient: Once more!\n');
caretaker.undo();

let messageMemento: string = 'Hello World,This is a typescript!,涂聚文 Geovin Du.Web';
document.body.innerHTML = messageMemento+",<br/>one="+pubMemento1+",<br/>two="+pubMemento2+",<br/>three="+pubMemento3+",<br/>four="+pubMemento4+",<br/>TypeScript Memento Pattern 备忘录模式";

  

调用:

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <head><title>TypeScript Hello Memento Pattern 备忘录</title>
      <meta name="Description" content="geovindu,涂聚文,Geovin Du"/>
<meta name="Keywords" content="geovindu,涂聚文,Geovin Du"/>
<meta name="author" content="geovindu,涂聚文,Geovin Du"/> 
    </head>
    <body>

        <script src="dist/Mementots.js">
 //
            //type="module"
        </script>

    </body>
</html>

  

 

输出: