Memento pattern

Definition

To record an object internal state without violating encapsulation and reclaim it later without knowledge of the original object.

Where to use & benefits

Let some info in an object to be available by another object by using default access control.
Save some info for later uses.
Need undo/redo features.
Used in database transaction.

Related patterns include

Command, which supports undo or redo features, whereas a memento keeps state of an object.
Iterator, which provides a way to access the elements of an aggregate object sequentially without exposing its underlying representation, whereas a memento can be used for iteration.

Example


To design a program with Memento feature is used to combine several design patterns like Command, Mediator or Iterator.

Here is an example expanded from Mediator example.

To show the Memento design concept, we record a dice number. This is very simple program. The Memento class just holds a number.
class Memento {
    int num;
    Memento(int c) {
       num = c;
    }
    int getNum() {
       return num;
    }
}

Then we combine Mediator and Command patterns to design three buttons and one label.The first button throws dice, the second button shows the dice number backward, and the third button clears number displayed. The label is used to display the dice number thrown. We use Math.random() method to get number from 1 to 6.
class BtnDice extends JButton implements Command {
    Mediator med;
    BtnDice(ActionListener al, Mediator m) {
        super("Throw Dice");
        addActionListener(al);
        med = m;
        med.registerDice(this);
    }
    public void execute() {
       med.throwit();
    }
}

class BtnClear extends JButton implements Command {
    Mediator med;
    BtnClear(ActionListener al, Mediator m) {
        super("Clear");
        addActionListener(al);
        med = m;
        med.registerClear(this);
    }
    public void execute() {
       med.clear();
    }
}
class BtnPrevious extends JButton implements Command {
    Mediator med;
    BtnPrevious(ActionListener al, Mediator m) {
        super("Previous");
        addActionListener(al);
        med = m;
        med.registerPrevious(this);
    }
    public void execute() {
       med.previous();
    }
}
class LblDisplay extends JLabel{
    Mediator med;
    LblDisplay (Mediator m) {
        super("0",JLabel.CENTER);
        med = m;
        med.registerDisplay(this);
        setBackground(Color.white);
        setBorder(new EtchedBorder(Color.blue, Color.green));
        Font font = new Font("Arial",Font.BOLD,40);
        setFont(font);
    }
}

The Mediator class will hold these participating objects and manipulate their relationships.
class Mediator {
    BtnDice btnDice;
    BtnPrevious btnPrevious;
    BtnClear btnClear;
    LblDisplay show;
    java.util.List list, undo;
    boolean restart = true;
    int counter = 0, ct = 0;
    //....
    Mediator() {
       list = new ArrayList();
       undo = new ArrayList();
    }
    void registerDice(BtnDice d) {
        btnDice = d;
    }
    void registerClear(BtnClear c) {
        btnClear = c;
    }
    void registerPrevious(BtnPrevious p) {
        btnPrevious = p;
    }
    void registerDisplay(LblDisplay d) {
        show = d;
    }
    void throwit() {
       show.setForeground(Color.black);
       int num = (int)(Math.random()*6 +1);
       int i = counter++;
       list.add(i, new Integer(num));
       undo.add(i, new Memento(num));
       show.setText(""+num);
    }
   
    void previous() {
       show.setForeground(Color.red);
       btnDice.setEnabled(false);
       if (undo.size() > 0) {      
           ct = undo.size()-1;
           Memento num = (Memento)undo.get(ct);
           show.setText(""+num.getNum());
           undo.remove(ct);
       }
       if (undo.size() == 0)
           show.setText("0");
    }
    void clear() {
        list = new ArrayList();
        undo = new ArrayList();
        counter = 0;
        show.setText("0");
        btnDice.setEnabled(true);
    }  
}

Finally, write a demo class.
class MementoDemo extends JFrame implements ActionListener {
    Mediator med = new Mediator();
    MementoDemo() {
       JPanel p = new JPanel();
       p.add(new BtnDice(this,med));
       p.add(new BtnPrevious(this,med));
       p.add(new BtnClear(this,med));
       JPanel dice = new JPanel();
       LblDisplay lbl = new LblDisplay(med);
       dice.add(lbl);
       getContentPane().add(dice, "Center");
       getContentPane().add(p, "South");
       setTitle("Memento pattern example");
       setDefaultCloseOperation(EXIT_ON_CLOSE);
       setSize(400,200);
       setVisible(true);
    }
    public void actionPerformed(ActionEvent ae) {
        Command comd = (Command)ae.getSource();
        comd.execute();
    }
    public static void main(String[] args) {
        new MementoDemo();
    }
}

The complete workable program is as follows. Copy it, compile it and run it.
import javax.swing.*;
import java.awt.event.*;
import java.awt.FontMetrics;
import java.awt.*;
import java.util.*;
import javax.swing.border.*;

interface Command {
    void execute();
}
class Mediator {
    BtnDice btnDice;
    BtnPrevious btnPrevious;
    BtnClear btnClear;
    LblDisplay show;
    java.util.List list, undo;
    boolean restart = true;
    int counter = 0, ct = 0;
    //....
    Mediator() {
       list = new ArrayList();
       undo = new ArrayList();
    }
    void registerDice(BtnDice d) {
        btnDice = d;
    }
    void registerClear(BtnClear c) {
        btnClear = c;
    }
    void registerPrevious(BtnPrevious p) {
        btnPrevious = p;
    }
    void registerDisplay(LblDisplay d) {
        show = d;
    }
    void throwit() {
       show.setForeground(Color.black);
       int num = (int)(Math.random()*6 +1);
       int i = counter++;
       list.add(i, new Integer(num));
       undo.add(i, new Memento(num));
       show.setText(""+num);
    }
   
    void previous() {
       show.setForeground(Color.red);
       btnDice.setEnabled(false);
       if (undo.size() > 0) {      
           ct = undo.size()-1;
           Memento num = (Memento)undo.get(ct);
           show.setText(""+num.getNum());
           undo.remove(ct);
       }
       if (undo.size() == 0)
           show.setText("0");
    }
    void clear() {
        list = new ArrayList();
        undo = new ArrayList();
        counter = 0;
        show.setText("0");
        btnDice.setEnabled(true);
    }
   
}
class BtnDice extends JButton implements Command {
    Mediator med;
    BtnDice(ActionListener al, Mediator m) {
        super("Throw Dice");
        addActionListener(al);
        med = m;
        med.registerDice(this);
    }
    public void execute() {
       med.throwit();
    }
}

class BtnClear extends JButton implements Command {
    Mediator med;
    BtnClear(ActionListener al, Mediator m) {
        super("Clear");
        addActionListener(al);
        med = m;
        med.registerClear(this);
    }
    public void execute() {
       med.clear();
    }
}
class BtnPrevious extends JButton implements Command {
    Mediator med;
    BtnPrevious(ActionListener al, Mediator m) {
        super("Previous");
        addActionListener(al);
        med = m;
        med.registerPrevious(this);
    }
    public void execute() {
       med.previous();
    }
}
class Memento {
    int num;
    Memento(int c) {
       num = c;
    }
    int getNum() {
       return num;
    }
}
class LblDisplay extends JLabel{
    Mediator med;
    LblDisplay (Mediator m) {
        super("0",JLabel.CENTER);
        med = m;
        med.registerDisplay(this);
        setBackground(Color.white);
        setBorder(new EtchedBorder(Color.blue, Color.green));
        Font font = new Font("Arial",Font.BOLD,40);
        setFont(font);
    }
}
class MementoDemo extends JFrame implements ActionListener {
    Mediator med = new Mediator();
    MementoDemo() {
       JPanel p = new JPanel();
       p.add(new BtnDice(this,med));
       p.add(new BtnPrevious(this,med));
       p.add(new BtnClear(this,med));
       JPanel dice = new JPanel();
       LblDisplay lbl = new LblDisplay(med);
       dice.add(lbl);
       getContentPane().add(dice, "Center");
       getContentPane().add(p, "South");
       setTitle("Memento pattern example");
       setDefaultCloseOperation(EXIT_ON_CLOSE);
       setSize(400,200);
       setVisible(true);
    }
    public void actionPerformed(ActionEvent ae) {
        Command comd = (Command)ae.getSource();
        comd.execute();
    }
    public static void main(String[] args) {
        new MementoDemo();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值