Follow treslines by email clicking Here!

Friday, August 22, 2014

Programming Design Pattern - Memento Pattern Applied - Best Practise

Hi there!

Today i'm gonna show the Memento design pattern in action. The Memento design pattern is a very useful programming design pattern whenever you need to perform save, undo and restore functions.

I'm assuming here you already know the concepts and i'll be focusing on practise. The example i will provide is a nice way to show it how it could looks like. You can always come back here, take it, adapt it and use it in your applictions as you may need. So be sure you bookmark it or join the group here on the right side of this post subscribing it.

First of all, let's take a look at the UML diagram of it. After that we will take the analogy for our example.

The UML Diagram of the Memento Pattern


Pay close attention, because once you understand that, everything will become clear and simple to understand. That's the reason I'm putting always the UML first. That way you'll get an eye for it with the time.





The example

In our example we will see, how we could perform save and undo actions restoring objects from a text file.

The Memento

That's the generic interface you could use while dealing with memento's capabilities. We will implement the memento on the fly in the Originator bellow. In other words, as soon as we need it in line.

// 1 STEP: DEFINE THE MEMENTO 
public interface Memento < T > {
    T getMemento();
    void setMemento(T state);
}

The Originator

That's the generic interface we will use to implement the Originator. I will create it also on the fly in the client. In a few seconds bellow. :)

//2 STEP: DEFINE THE ORIGINATOR 
public interface Save < T > extends Memento < T > {
    Memento < T > save();
    void restore(Memento < T > memento);
}

The Interface Undo

That's the generic interface we will use to create the care taker. I will create it also on the fly in the client. Be patient. :)

//3 STEP: DEFINE THE CARETAKER
public interface Undo < T > {
    public void addMemento(Memento < T > state) ;
    public Memento < T > getMemento(int index);
}

The concrete CareTaker

That's the abstract implementation of the generic interface. I will create it also on the fly in the client. Stay tuned. :)

//4 STEP: IMPLEMENT A ABSTRACTCARATAKER
public abstract class UndoCareTaker < T > implements Undo < T > {
    private List < Memento < T > > mementoList = new ArrayList < Memento < T > > ();
    public void addMemento(Memento < T > state) {
        if (state != null) {
            mementoList.add(state);
        }
    }
    public Memento < T > getMemento(int index) {
        int min = 0;
        int max = mementoList.size()-1;
        if(mementoList.isEmpty()){
            String msg = "CareTaker has no entry! Passed index:";
            throw new IndexOutOfBoundsException(msg + index);
        }
        if(!(index > = min && index < = max)){
            String msg = "Passed index:"+index+" > Allowed index range: ";
            throw new IndexOutOfBoundsException(msg + min + " - " + max);
        }
        return mementoList.get(index);
    }
}

The Originator Ifself

That's the abstract implementation of the interface generic interface Save.

//5 STEP: IMPLEMENT A ABSTRACTORIGINATOR
public abstract class SaveOriginator < T > implements Save < T >{
    private T state;
    public void setMemento(T state) {this.state = state;}
    public T getMemento() {return state;}
    public void restore(Memento < T > memento) {setMemento(memento.getMemento());}
    public Memento < T > save() {
        Memento < T > memento = new Memento < T > () { // created on the fly as i promissed! :)
            private T state;
            @Override
            public void setMemento(T state) {this.state = state;}
            @Override
            public T getMemento() {return state;}
        };
        memento.setMemento(state);
        return memento;
    }
}

The Test

Finally, let's see how it works in practise.

public class Client {
    public static void main(String[] args) {
        Save < String > originator = new SaveOriginator < String > (){};//created on the fly
        Undo < String > careTaker = new UndoCareTaker < String > (){};//created on the fly
        originator.setMemento("State #1");
        originator.setMemento("State #2");
        careTaker.addMemento(originator.save());
        originator.setMemento("State #3");
        careTaker.addMemento(originator.save());
        originator.setMemento("State #4");
        System.out.println("Current State: " + originator.getMemento());
        originator.restore(careTaker.getMemento(0));
        System.out.println("First saved State: " + originator.getMemento());
        originator.restore(careTaker.getMemento(1));
        System.out.println("Second saved State: " + originator.getMemento());
    }
}

That's all! Hope you like it!

No comments:

Post a Comment