5

我对纪念品应该如何实施感到非常困惑。

我了解Memento有一个State备忘录模式用于存储不同的(以前的)状态以便可以将对象恢复到以前的状态

好吧,假设我有多个对象,每个对象都有 10 个属性,其中 5 个在每个对象的生命周期中保持不变,但其中 5 个会发生变化。所以我需要,为每个对象保存它以前的状态并返回它们。

问题:

如何对这些对象应用备忘录模式?

到目前为止我的想法:

所以Memento Pattern有 3 个类,你创建了很多Memento,每个状态一个。存储对象 AKA Mementos的所有先前状态的看守者。然后是创建Mementos并从Memento获取状态的Originator

这意味着每个对象实例都需要它自己的看守人实例(它以前状态的列表),并且这个看守人将拥有带有该对象的 5 个属性的以前状态的纪念品(以及当前状态还是只有以前的状态?),但是所有具有看守者的对象都可以使用相同的Originator 实例,因为可以使用Originator为任何看守者创建新的纪念品。

这是如何实施还是我误解了它?

它看起来像这样:

Originator 和 Memento 类

public class Memento {
   private Object1Attributes state;

   public Memento(Object1Attributes state){
      this.state = state;
   }

   public Object1Attributes getState(){
      return state;
   }    
}


static class Originator {
   private Object1Attributes state;

   public Memento saveStateToMemento(){
      return new Memento(state);
   }

   public void getStateFromMemento(Memento Memento){
      state = Memento.getState();
   }

   public void setState(Object1Attributes state){
      this.state = state;
   }

   public Object1Attributes getState(){
      return state;
   }

}

其他对象

public class Object1Attributes{
    string attribute1;
    int attribute2;
    someObject attribute3;
    someObject attribute4;
    someObject attribute5;
}

public class Object1 {

    CareTaker careTaker = new CareTaker();

    Object1Attributes;

    string attribute6;
    int attribute7;
    someObject attribute8;
    someObject attribute9;
    someObject attribute10;


    public void returnToPreviousState(){
        if(caretaker.Length()>0){
            Object1Attributes = originator.getStateFromMemento(careTaker.get(caretaker.Length()-1));
            caretaker.remove(caretaker.Length()-1);
        }
   }

    public void newState(ObjectAttributes OA){
        originator.setState(OA);
        this.ObjectAttributes = OA;
        this.caretaker.add(originator.saveStateToMemento());

    }

}

另外的选择

将使 Memento 类和 Originator 类拥有 5 个属性,而不是将 5 个属性封装在另一个类中。像这样:

public class Originator {
    string attribute1;
    int attribute2;
    someObject attribute3;
    someObject attribute4;
    someObject attribute5;

   public Memento saveStateToMemento(){
      return new Memento(attribute1, attribute2, attribute3, attribute4, attribute5);
   }

   public void setAttribute1(string state){
      this.attribute1 = state;
   }

   public void setAttribute2(int state){
      this.attribute2 = state;
   }

}

这样,每个 Object1 实例都将拥有自己的 Originator 实例而不是 Object1Attributes,并且此 Originator 将包含 object1 实例中属性的当前状态;我不知道哪种方式是实现模式的正确方式。

所有在线示例都使用 mementos 来存储只是一个字符串的“状态”,它们都不涉及创建可以具有多个状态的多个对象,所以这就是我如此不确定的原因。

4

1 回答 1

1

实现 Memento 模式时的常见陷阱之一是暴露 Originator 的内部状态。这打破了称为封装的基本 OO 概念之一。

Memento 具有捕获 Originator 状态的状态。这可以是外部类型。您还可以在 Memento 本身中声明所需的属性。稍后您可以使用 Mediator 的状态将 Originator 恢复到该状态。

class Memento {
    var state: State
}

Originator 应具有两种与 Memento 相关的方法:

class Originator {
    func createMemento() -> Memento {
        let currentState = State(...)
        return Memento(state: currentState)
    }

    func apply(memento: Memento) {
        let restoreState = memento.state
        //...set the properties you want to restore from the memento state
    }
}

最后,看门人:

final class Caretaker {
    private lazy var mementos = [String: Memento]()

    func saveState(originator: Originator, identifier: String) {
        let snapshot: GameWorldMemento = originator.createMemento()
        snapshots[identifier] = snapshot
    }

    func restoreState(originator: Originator, identifier: String) {
        if let snapshot = snapshots[identifier] {
            originator.apply(memento: snapshot)
        }
    }
}

这是如何使用它:

let caretaker = CareTaker()
let originator = Originator()

// Save initial state
caretaker.saveState(originator: originator, identifier: "save0")

// modify the originator
// ...
// reset the originator to its original state
caretaker.restoreState(originator: originator, identifier: "save0")

这只是一个简化的例子来说明这个概念。

通常,我会从定义三个协议开始。由于具体的“发起者”通常已经存在类型,我会添加一个类型扩展以使其采用 Originator 协议。这样我就不必修改它的代码了。实际上,这样我可以在不修改其原始代码的情况下增强类型。

希望这可以帮助。

于 2017-11-09T14:03:33.067 回答