简体   繁体   中英

Memento pattern and violation of encapsulation

Across the internet I come across with examples of implementation of memento pattern which I consider are fully incorrect. They can be written in both Java and C#.

Here a several of them

  1. Incorrect implementation of Memento pattern 1
  2. Incorrect implementation of Memento pattern 2
  3. Incorrect implementation of Memento pattern 3

The code:

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; }
}

In code I left comments that should describe situation.

The caretaker class can read private field of originator through memento that violates one of the main principles of memento pattern:

The object's encapsulation must not be violated.

So the question is am I right?

So the question is am I right?

Yes, you are right: the examples are all incorrect implementations of the Memento design pattern, because the Memento class exposes its internal dependency through a public method. As you noted, this allows the Caretaker (or any other class) to gain private information about the Originator .

Previous answers focus on the state of the internal field and whether the Memento state can vary independently of the Originator . But encapsulation can be violated in more ways than by exposing state. It can also be violated by exposing dependencies. The public getter method exposes the dependency that Originator has on String .

I wish I could say that misinformation is unusual regarding design patterns; but you will find inaccurate and misleading articles about design patterns across the Internet, including here on SO and on Wikipedia .

I happen to like https://refactoring.guru/design-patterns/memento but it's never a bad idea to crosscheck against the GoF book.

Encapsulation doesn't mean that you shouldn't be able to access the data at all, you just shouldn't be able to access it directly. You should only be able to access it via public methods :)
This link is probably able to explain it better than i am:

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

So encapsulation is kept in your code example, since the state can only be retrieved via a public get method.

If we add some logic to check how the variables evolve, you will notice how Originator and Memento are not sharing the same data.

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;
    }
}

Now lets work with them:

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);

You will notice that memento1_state and memento2_state are different, because they do not share the same underlying object.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM