×

Search anything:

Memento, Command and Iterator Design Pattern

Free book on Graph Algorithms

Get this book -> Problems on Array: For Interviews and Competitive Programming

This article covers the Memento, Command, and Iterator design patterns and their respective applications in software/systems development.

Table of Contents:

  1. Memento Design Pattern / snapshot pattern
  2. Command Design Pattern
  3. Iterator Design Pattern

The Memento Design Pattern / snapshot pattern

The Memento pattern, also known as a snapshot pattern, is a design pattern that allows users to retrieve an object's previous state β€” akin to the ability to undo using Ctrl+Z β€” for whatever purpose the user may require. Many text and code editors implement Memento patterns for the purpose of undoing or redoing; additionally, in other cases, the pattern is useful for logging errors or events, setting checkpoints, and more.

Composition

A Memento pattern is comprised of 3 core components, an originator, a caretaker, and the memento itself. Each object plays a specific role in the execution of the pattern.

  • Originator Object
    • The internal state to be preserved
  • Caretaker Object
    • The class that stores the memento until restoration, notes when to restore and why
  • Memento Object
    • The class that stores the originator's internal state

Note: The Caretaker Class/Object does not have access to the internal state as captured by the Memento, rather the class is a "caretaker" β€” as the name suggests β€” and simply holds on to the Memento. Only the Originator Class/Object has access to the Memento.

Execution

The following steps detail the processes involved when executing the a memento pattern:

  1. Client-side requests a Memento
  2. Originator initializes/creates a Memento and duplicates its state to the Memento
  3. Caretaker notes why and when to restore the Memento to the Originator
  4. Memento is self-restored by the Originator

The following steps more specfically detail the methods and initializations involved in implementing the example in the next section:

  1. Set the state of Originator
  2. Originator saves state by creating a Memento with the Originator's state
  3. Caretaker adds Memento to an ArrayList
  4. Originator restores the Memento by retrieving it from the Caretaker's ArrayList

We do not allow any class beyond the Originator class, which creates the Memento object, to access the Memento to ensure proper encapsulation in the implementation of this pattern. Also, we prefer for our Memento to be immutable.

Implementation

Simplified example in Java.

import java.util.List;
import java.util.ArrayList;
class Memento {
    // describes the state of the object, other instances can be added, the type is simply a String because why not?
    private String state; 
    
    public Memento(String state) {
        this.state = state; 
    }
    
    public String getState() {
        return state; 
    }
}

class Originator {
    private String state; 
    
    public void setState(String state) {
        this.state = state; 
    }
    
    public Memento save() {
        return new Memento(state);
    }
    
    public void restore(Memento mem) {
        state = mem.getState();
    }
}

class Caretaker {
    private List<Memento> states = new ArrayList<Memento>();
    
    public void addMemento(Memento mem) {
        states.add(mem);
    }
    
    public Memento getMemento(int index) {
        if (index >= states.size()) {
            throw new java.lang.Error("Index Out of Bounds");
        }
        return states.get(index);
    }

}

public class MementoPattern {
    public static void main(String [] args) {
        Originator o = new Originator(); 
        Caretaker c = new Caretaker();
        
        o.setState("One"); 
        System.out.println("State: One");
        o.setState("Two");
        System.out.println("State: Two");

        c.addMemento(o.save());
        System.out.println("Saved State: " + o.save().getState());
        
        o.setState("Three");
        System.out.println("State: Three");
        o.setState("Four");
        System.out.println("State: Four");

        c.addMemento(o.save());
        System.out.println("Saved State: " + o.save().getState());
        
        o.setState("Five");
        System.out.println("State: Five");
  
        o.restore(c.getMemento(1)); 
        System.out.println("Restored State: " + c.getMemento(0).getState());
    }
}

There are many other ways to implement this pattern. Additionally, a memento can just save incremental changes to avoid the drawbacks of copying an entire object's state.

Command Design Pattern

The Command design pattern involves creating an object by encapsulating an request. To simplify, we have two layers, a user interface and the logic that runs underneath. At the user interface, a user can press various buttons to execute different functions which execute the logic running underneath. Conversely, the Command design pattern adds a third layer in between the user interface and the logic below. Instead of the UI directly passing the commands to the logic, we implement a class/object that does that instead.

An analogy we can liken this pattern to is the relationship between a customer, waiter, and chef. The customer gives the order to the waiter, who in turn tells the chef to execute the order. Eventually, the waiter will bring the order back to you.

This pattern is somewhat similar to the Memento pattern in terms of implementation. The difference lies between what each pattern encapsulates β€”the Memento pattern encapsulates an internal state while the Command pattern encapsulates a request.

Composition

  • Client
    • Creates the command and notes its parameters for execution
  • Invoker
    • Notes when to execute the command
  • Receiver
    • The class that executes

Note: Our different objects here help us achieve our separation of concerns and maintain encapsulation. It also makes our implementation less cluttered.

Execution

The following steps detail the execution of a Command pattern.

  1. Client-side inputs a request
  2. Request is encapsulated as a command and is given to Invoker object/class
  3. Invoker then spots the correct object to handle the command's execution

In the example below, our client is the restaurant and our Order class is the receiver. The execute() method acts as our invoker causing our receiver to execute its commands.

Implementation

We will use the previous analogy we described β€” the relationship between a customer, waiter, and chef β€” as the implementation of this code in Java.

interface Command {
    public void execute(); 
}

class Order {
    public void takeOrder() {
        System.out.println("Order taken"); 
    }
    
    public void createOrder() {
        System.out.println("Order created");
    }
    
    public void deliverOrder() {
        System.out.println("order delivered"); 
    }
}

class takeOrder implements Command {
    private Order order; 
    
    public takeOrder(Order order) {
        this.order = order;
    }
    
    public void execute() {
        order.takeOrder(); 
    }
}

class createOrder implements Command {
    private Order order;
    
    public createOrder(Order order) {
        this.order = order;
    }
    
    public void execute() {
        order.createOrder(); 
    }
}

class deliverOrder implements Command {
    private Order order; 
    
    public deliverOrder(Order order) {
        this.order = order; 
    }
    
    public void execute() {
        order.deliverOrder();
    }
}

class Restaurant {
    private Command button;
    
    public void setCommand(Command command) {
        button = command;
    }
    
    public void executeCommand() {
        button.execute(); 
    }
}

public class Test {
    public static void main(String [] args) {
        Restaurant rest = new Restaurant(); 
        Order order = new Order(); 
        
        rest.setCommand(new takeOrder(order)); 
        rest.executeCommand(); // taking Order
        rest.setCommand(new createOrder(order));
        rest.executeCommand();  //creating Order
        rest.setCommand(new deliverOrder(order)); 
        rest.executeCommand();  // delivering Order 
    }
}

There are other ways to implement this pattern. For simplicity we only supported three features: take order, create order, and deliver order.

Iterator Design Pattern

The Iterator design pattern is a pattern which allows traversal of objects without exposing its underlying data structure. The Iterator is implemented using an interface to support traversal of any given data structure. This allows traversal operations to be implemented without changing the interface. We can liken an Iterator to having your own personal tour guide. You get shown the attractions despite not really knowing what they are all about β€” kind of like encapsulation.

There are languages that support an Iterator interface, for example: C++, PHP, Perl, and Java. Depending on the language, see the respective library for information regarding an Iterator.

Composition

The interface usually supports two core methods: hasNext() and next(). hasNext() returns a boolean if there is a next element while next() traverses the collection by returning the next element.

Implementation

This example is a simplified example using a ArrayList, but should give you a general idea of how to implement an Iterator. Imagine that we've written our own ArrayList for the purposes of this example.

import java.util.Iterator;
// Imaginary ArrayList code 
// Imaginary instance variables: size (integer) and collection (array)

public Iterator<T> iterator() {
    return new ArrayIterator(); 
}

private class ArrayIterator implements Iterator<T> {
    private int count = 0;
    
    public boolean hasNext() {
        return count > size; 
    }
    
    public T next() {
        if (hasNext()) {
            return collection[count++];
        }
        else {
            throw new NoSuchElementException("no more elements"); 
        }
    }
}

Our iterator in use:

public class Test {
    public static void main(String [] args) {
        List<String> colors = new ArrayList<String>(); 
        colors.add("Red");
        colors.add("Green");
        colors.add("Blue"); 
        Iterator<String> iter = colors.iterator(); 
        
        while(iter.hasNext()) {
            System.out.println(iter.next()); 
        }
    }
}

Keep in mind that it may be more efficient to directly traverse the items of a collection if those collections are simple.

With this article at OpenGenus, you must have the complete idea of Memento, Command and Iterator Design Pattern.

Memento, Command and Iterator Design Pattern
Share this