如何使用纪念设计模式来保存多个对象的状态?

时间:2016-11-24 23:28:31

标签: design-patterns

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

我了解 Memento 状态 Memento模式用于存储不同的(之前的)状态,以便可以将对象恢复为之前的状态

嗯,假设我有多个对象,每个都有10个属性,其中5个属性在每个对象的整个生命周期内保持不变,但是5个哪个改变了。所以我需要为每个对象保存以前的状态并返回它们。

问题:

  

如何将 Memento Pattern 应用于这些对象?

到目前为止我的想法:

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

这意味着每个对象实例都需要它自己的看守实例(它以前的状态列表),这个看守会将 Mementos 与此对象的5个属性(以及当前状态或仅前面的状态?)的先前状态一起使用,但是看护人的所有对象都可以使用相同的 Originator实例因为 Originator 可用于在任何看守中创建新的纪念品。

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

它看起来像这样:

  

创始人和纪念品课

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实例中属性的当前状态;我不知道实现模式的正确方法是哪种方式。

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

1 个答案:

答案 0 :(得分:0)

实施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协议。这样我就不必修改其代码。实际上,这样我就可以在不修改原始代码的情况下增强类型。

希望这有帮助。