Java中的Memento设计模式


今天,我想讨论另一个称为Memento Design Pattern的行为设计模式,该模式用于将对象的状态恢复到先前的状态。

纪念品设计模式

  • 该备忘录 的设计模式是23熟知的一个GoF的设计模式提供一个对象恢复到以前的状态的能力。
  • 该备忘录设计模式的:与三个对象的帮助下实现的鼻祖,一个看守,和纪念品。
  • Originator—我们要存储其内部状态的对象。该发起人 对象创建一个备忘录对象存储其内部状态。因此,Originator 对象知道如何保存和恢复自身。获取并设置Memento 对象的值的对象。
  • Caretaker -它知道为什么当对象发起人 需要保存和恢复本身。在物体上的操作始发 同时具有回滚的可能性。它保留了创建的Memento 对象的历史记录。看守政府采取的快照鼻祖 操作之前。
  • Memento-包含基本state存储和检索功能的POJO对象。 记忆对象通常是不可变 的。该对象保留了始发者的内部状态,并允许其还原它。
  • Memento模式的经典示例是 伪随机数生成器或有限状态机。
  • Git隐藏是Memento设计模式的另一个示例。
  • Originator 对象的内部状态应保存在外部,以便以后可以将其恢复为该状态。同样,不得违反对象的封装。
    • 该看守请求纪念品 从发端 操作之前。并使用该备忘录 的恢复发端 如果需要到以前的状态。
  • 通过使用序列化,我们可以使Memento Design Pattern的实现更加通用;这样就消除了每个班级有自己的Memento 班级的要求。
  • 备忘录设计模式也可以与命令设计模式一起使用,以实现命令的撤消 。

mementodesignpattern.png

为了理解Memento设计模式,我们以Employee 类为例, 它使用EmployeeMemento 类存储和检索其状态。

使用Memento设计模式的员工类别存储状态

员工类别的代码:

package org.trishinfotech.memento;
public class Employee {
    protected int empId;
    protected String name;
    protected String designation;
    protected long salary;
    protected String department;
    protected String project;

    public Employee(int empId) {
        super();
        this.empId = empId;
    }

    public int getEmpId() {
        return empId;
    }
    public String getName() {
        return name;
    }
    public Employee setName(String name) {
        this.name = name;
        return this;
    }
    public String getDesignation() {
        return designation;
    }
    public Employee setDesignation(String designation) {
        this.designation = designation;
        return this;
    }
    public long getSalary() {
        return salary;
    }
    public Employee setSalary(long salary) {
        this.salary = salary;
        return this;
    }
    public String getDepartment() {
        return department;
    }
    public Employee setDepartment(String department) {
        this.department = department;
        return this;
    }
    public String getProject() {
        return project;
    }
    public Employee setProject(String project) {
        this.project = project;
        return this;
    }
    @Override
    public String toString() {
        return "Employee [empId=" + empId + ", name=" + name + ", designation=" + designation + ", salary=" + salary
                + ", department=" + department + ", project=" + project + "]";
    }
    public EmployeeMemento createMemento() {
        return new EmployeeMemento(empId, name, designation, salary, department, project);
    }
    public void restore(EmployeeMemento memento) {
        if (memento != null) {
            this.empId = memento.empId;
            this.name = memento.name;
            this.designation = memento.designation;
            this.salary = memento.salary;
            this.department = memento.department;
            this.project = memento.project;
        } else {
            System.err.println("Can't restore without memento object!");
        }
    }
}

在这里,我们可以看到发起者Employee 类创建并还原了Employee Memento。就像您看到的那样,我仅在创建Employee 对象时才设置了EmpId ,并且我希望保持EmpId 唯一。

EmployeeMemento 类的代码:

package org.trishinfotech.memento;
public class EmployeeMemento {
    protected int empId;
    protected String name;
    protected String designation;
    protected long salary;
    protected String department;
    protected String project;
    public EmployeeMemento(int empId, String name, String designation, long salary, String department, String project) {
        super();
        this.empId = empId;
        this.name = name;
       this.designation = designation;
        this.salary = salary;
        this.department = department;
        this.project = project;
    }
    public int getEmpId() {
        return empId;
    }
    public String getName() {
        return name;
    }
    public String getDesignation() {
        return designation;
    }
    public long getSalary() {
        return salary;
    }

    public String getDepartment() {
        return department;
    }
    public String getProject() {
        return project;
    }
    @Override
    public String toString() {
        return "EmployeeMemento [empId=" + empId + ", name=" + name + ", designation=" + designation + ", salary="
                + salary + ", department=" + department + ", project=" + project + "]";
    }
}

现在为EmployeeCaretaker 类编写代码:

package org.trishinfotech.memento;
import java.util.HashMap;
import java.util.Map;
public class EmployeeCaretaker {
    protected Map<Integer, Map<String, EmployeeMemento>> mementoHistory = new HashMap<Integer, Map<String, EmployeeMemento>>();

    public void addMemento(int empId, String mementoMessage, EmployeeMemento memento) {
        if (mementoMessage != null && mementoMessage.trim().length() != 0 && memento != null) {
            Map<String, EmployeeMemento> mementoMessageMap = mementoHistory.get(empId);
            if (mementoMessageMap == null) {
                mementoMessageMap = new HashMap<String, EmployeeMemento>();
                mementoHistory.put(empId, mementoMessageMap);
            }
            mementoMessageMap.put(mementoMessage, memento);
            System.out.printf("Snapshot of employee name '%s' stored with message '%s'.\n", memento.getName(),
                    mementoMessage);
        }
    }

    public EmployeeMemento getMemento(int empId, String mementoMessage) {
        EmployeeMemento memento = null;
        if (mementoMessage != null && mementoMessage.trim().length() != 0) {
            Map<String, EmployeeMemento> mementoMessageMap = mementoHistory.get(empId);
            if (mementoMessageMap != null) {
                memento = mementoMessageMap.get(mementoMessage);
                if (memento != null) {
                    System.out.printf("Snapshot of employee name '%s' with message '%s' restored\n", memento.getName(),
                            mementoMessage);
                } else {
                    System.err.println("Not able to find the memento!");
                }
            }
        }
        return memento;
    }
    public void printStoredMementoObjects() {
        System.out.println("======================================================");
        mementoHistory.forEach((empId, mementoMessageMap) -> {
            mementoMessageMap.forEach((message, memento) -> {
                System.out.printf("EmpId: '%d', Message: '%s', Memento: '%s'\n", empId, message, memento);
            });
        });
        System.out.println("======================================================");
    }
}

我在存储Memento时使用EmpId和Message String作为键。在使用Memento恢复Employee时, 我将使用相同的方法。

现在,是时候编写Main 类来执行和测试输出了:

package org.trishinfotech.memento;
public class Main {
    public static void main(String[] args) {
        EmployeeCaretaker caretaker = new EmployeeCaretaker();
        System.out.println("creating employee objects with intial values");
        Employee racheal = new Employee(100).setName("Racheal").setDesignation("Lead").setSalary(100000).setDepartment("R&D").setProject("Transportation Management");
        Employee micheal = new Employee(101).setName("Micheal").setDesignation("Developer").setSalary(75000).setDepartment("Engineering").setProject("IoT");
        System.out.println(racheal);
        System.out.println(micheal);
        EmployeeMemento rachealMemento = racheal.createMemento();
        EmployeeMemento michealMemento = micheal.createMemento();
        caretaker.addMemento(racheal.getEmpId(), "Saved at intitial stage", rachealMemento);
        caretaker.addMemento(micheal.getEmpId(), "Saved at intitial stage", michealMemento);
        System.out.println("\nracheal got promotion");
        racheal.setDesignation("Manager").setSalary(120000);
        System.out.println("micheal assigned to another project.");
        micheal.setProject("Android App");
        System.out.println(racheal);
        System.out.println(micheal);
        rachealMemento = racheal.createMemento();
        michealMemento = micheal.createMemento();
        caretaker.addMemento(racheal.getEmpId(), "Saved at promotion", rachealMemento);
        caretaker.addMemento(micheal.getEmpId(), "Saved at android project", michealMemento);
        System.out.println("\nracheal got increment");
        racheal.setSalary(140000);
        System.out.println("micheal got promotion");
        micheal.setDesignation("Lead Developer").setSalary(90000);
        System.out.println(racheal);
        System.out.println(micheal);
        rachealMemento = racheal.createMemento();
        michealMemento = micheal.createMemento();
        caretaker.addMemento(racheal.getEmpId(), "Saved at increment", rachealMemento);
        caretaker.addMemento(micheal.getEmpId(), "Saved at promotion", michealMemento);
        System.out.println("\nLet's print the stored memento objects we have");
        caretaker.printStoredMementoObjects();
        System.out.println("\nnow for some reason, we like to revert racheal to initial stage.");
        System.out.println("and micheal to android project.");
        rachealMemento = caretaker.getMemento(racheal.getEmpId(), "Saved at intitial stage");
        michealMemento = caretaker.getMemento(micheal.getEmpId(), "Saved at android project");
        racheal.restore(rachealMemento);
        micheal.restore(michealMemento);
        System.out.println(racheal);
        System.out.println(micheal);
    }
}

以下是输出:

creating employee objects with intial values
Employee [empId=100, name=Racheal, designation=Lead, salary=100000, department=R&D, project=Transportation Management]
Employee [empId=101, name=Micheal, designation=Developer, salary=75000, department=Engineering, project=IoT]
Snapshot of employee name 'Racheal' stored with message 'Saved at intitial stage'.
Snapshot of employee name 'Micheal' stored with message 'Saved at intitial stage'.
racheal got promotion
micheal assigned to another project.
Employee [empId=100, name=Racheal, designation=Manager, salary=120000, department=R&D, project=Transportation Management]
Employee [empId=101, name=Micheal, designation=Developer, salary=75000, department=Engineering, project=Android App]
Snapshot of employee name 'Racheal' stored with message 'Saved at promotion'.
Snapshot of employee name 'Micheal' stored with message 'Saved at android project'.
racheal got increment
micheal got promotion
Employee [empId=100, name=Racheal, designation=Manager, salary=140000, department=R&D, project=Transportation Management]
Employee [empId=101, name=Micheal, designation=Lead Developer, salary=90000, department=Engineering, project=Android App]
Snapshot of employee name 'Racheal' stored with message 'Saved at increment'.
Snapshot of employee name 'Micheal' stored with message 'Saved at promotion'.
Let's print the stored memento objects we have
======================================================
EmpId: '100', Message: 'Saved at increment', Memento: 'EmployeeMemento [empId=100, name=Racheal, designation=Manager, salary=140000, department=R&D, project=Transportation Management]'
EmpId: '100', Message: 'Saved at intitial stage', Memento: 'EmployeeMemento [empId=100, name=Racheal, designation=Lead, salary=100000, department=R&D, project=Transportation Management]'
EmpId: '100', Message: 'Saved at promotion', Memento: 'EmployeeMemento [empId=100, name=Racheal, designation=Manager, salary=120000, department=R&D, project=Transportation Management]'
EmpId: '101', Message: 'Saved at intitial stage', Memento: 'EmployeeMemento [empId=101, name=Micheal, designation=Developer, salary=75000, department=Engineering, project=IoT]'
EmpId: '101', Message: 'Saved at android project', Memento: 'EmployeeMemento [empId=101, name=Micheal, designation=Developer, salary=75000, department=Engineering, project=Android App]'
EmpId: '101', Message: 'Saved at promotion', Memento: 'EmployeeMemento [empId=101, name=Micheal, designation=Lead Developer, salary=90000, department=Engineering, project=Android App]'
======================================================
now for some reason, we like to revert racheal to initial stage.
and micheal to android project.
Snapshot of employee name 'Racheal' with message 'Saved at intitial stage' restored
Snapshot of employee name 'Micheal' with message 'Saved at android project' restored
Employee [empId=100, name=Racheal, designation=Lead, salary=100000, department=R&D, project=Transportation Management]
Employee [empId=101, name=Micheal, designation=Developer, salary=75000, department=Engineering, project=Android App]

我希望通过示例,我们对Memento Design Pattern的实现有一个清晰的认识。


原文链接:http://codingdict.com