0

在互联网上,我遇到了一些我认为完全不正确的备忘录模式的实现示例。它们可以用 Java 和 C# 编写。

这里有几个

  1. Memento 模式 1 的错误实现
  2. Memento 模式 2 的错误实现
  3. Memento 模式 3 的错误实现

编码:

public class Originator
{
    private string _state; //the private field of originator that shouldn't be exposed!!!!

    public Memento CreateMemento()
    {
        return new Memento(_state);
    }

    public void SetMemento(Memento memento)
    {
        _state = memento.GetState();
    }
}


public class Memento
{
    private string _state;

    public Memento(string state)
    {
        _state = state;
    }

    public string GetState()
    {
        return _state;  // here caretaker can access to private field of originator!!!
    }
}


public class Caretaker
{
    public Memento Memento { get; set; }
}

在代码中,我留下了应该描述情况的注释。

caretaker 类可以通过 memento 读取始发者的私有字段,这违反了 memento 模式的主要原则之一:

不得违反对象的封装。

所以问题是我是对的吗?

4

3 回答 3

1

所以问题是我是对的吗?

是的,您是对的:这些示例都是 Memento 设计模式的错误实现,因为Memento该类通过公共方法暴露了其内部依赖关系。正如您所指出的,这允许Caretaker(或任何其他类)获取有关Originator.

以前的答案集中在内部场的状态以及Memento状态是否可以独立于Originator. 但是,与暴露状态相比,违反封装的方式更多。暴露依赖关系也可能违反它。公共 getter 方法公开了OriginatorString.

我希望我可以说关于设计模式的错误信息是不寻常的。但是您会在 Internet 上找到关于设计模式的不准确和误导性文章,包括在 SO 和Wikipedia上。

我碰巧喜欢https://refactoring.guru/design-patterns/memento,但对照 GoF 书进行交叉检查绝不是一个坏主意。

于 2020-03-25T21:16:33.987 回答
0

封装并不意味着您根本不能访问数据,您只是不能直接访问它。您应该只能通过公共方法访问它:)
这个链接可能比我能更好地解释它:

https://www.geeksforgeeks.org/encapsulation-in-java/

因此,封装保留在您的代码示例中,因为只能通过公共 get 方法检索状态。

于 2020-03-25T11:29:44.977 回答
0

如果我们添加一些逻辑来检查变量如何演变,您会注意到如何共享OriginatorMemento不共享相同的数据。

public class Originator
{
    private string _state = "originator_initial_state";

    public Memento CreateMemento()
    {
        return new Memento(_state);
    }

    public void DoSomeLogic()
    {
        _state = _state + " modified";
    }

    public void SetMemento(Memento memento)
    {
        _state = memento.GetState();
    }
}

public class Memento
{
    private string _state;

    public Memento(string state)
    {
        _state = state;
    }

    public string GetState()
    {
        return _state;
    }
}

现在让我们与他们合作:

Originator myOriginator = new Originator();
Memento memento1 = myOriginator.CreateMemento();

myOriginator.DoSomeLogic();

Memento memento2 = myOriginator.CreateMemento();

string memento1_state = memento1.GetState();
string memento2_state = memento2.GetState();

Console.WriteLine(memento1_state);
Console.WriteLine(memento2_state);

您会注意到memento1_statememento2_state是不同的,因为它们共享相同的底层对象。

于 2020-03-25T12:00:59.487 回答