/ OOD

[365 วันแห่งโปรแกรม #day63] Memento pattern

วันที่หกสิบสามของ ‪#‎365วันแห่งโปรแกรม Memento pattern


Memento pattern

Memento pattern เป็นแพทเทิร์นที่ว่าด้วยการสร้างช่องทางการ restore state ของ object กลับไปเป็น state ก่อนหน้า (undo หรือ rollback)

แพทเทิร์นนี้จะมีส่วนประกอบ 3 ชิ้นคือ Originator, Caretaker และ Memento

  • Originator เป็น object ที่เราต้องการจะเซฟ state

  • Memento เป็นกล่องสำหรับเก็บ state ของ Originator

  • Caretaker เป็น object ที่ใช้จัดการ Memento ว่าจะเก็บเมื่อไหร่ เก็บแค่ไหน

หลังจากดูส่วนประกอบไปอาจจะยังไม่เข้าใจเท่าไหร่ งั้นคงต้องดู Diagram กันหน่อย

Memento pattern

จาก diagram จะเห็นว่า Memento จะมีการเก็บ state ที่เหมือนกับ Originator เลย และ Caretaker เป็นคนเก็บ instance ของ Memento เอาไว้

อย่างไรก็ตามแพทเทิร์นนี้ไม่ได้มีการ implement ที่ตายตัว บางครั้งเราอาจจะไม่ implement Caretaker ก็ได้ โดยการย้ายส่วนเก็บ Memento ไปไว้ที่ Client หรือ Originator เองเลย

ตัวอย่างการการนำไปใช้

สมมติว่ามีคลาสๆ นึงที่มี property string ซึ่งสามารถเปลี่ยนแปลงค่าได้ เราต้องการเก็บการเปลี่ยนแปลงที่เกิดขึ้น เพื่อที่จะได้สามารถย้อนกลับไปยังค่าก่อนหน้า ดังนั้นเราจะนำ Memento pattern มาใช้ดังนี้

ขั้นแรกเราต้องสร้าง class ของสิ่งที่เราต้องการเก็บ state ก่อน (Originator)

public class Originator {
   private String state;

   public void setState(String state){
      this.state = state;
   }

   public String getState(){
      return state;
   }
}

ต่อมาเราก็ต้องสร้างคลาสสำหรับเก็บ state ของ Originator (Memento)

public class Memento {
    private String state;

    public Memento(String state){
        this.state = state;
    }

    public String getState(){
        return state;
    }	
}

ใน Memento ก็จะมี member เหมือนกับ originator เลย

ต่อมาเราก็จะมาแก้ให้ Originator สามารถสร้าง Memento เพื่อเก็บ state

public class Originator {

    ...

    public Memento saveStateToMemento(){
        return new Memento(state);
    }

    public void getStateFromMemento(Memento Memento){
        state = Memento.getState();
    }
}

โค้ดด้านบนเป็นการสร้างเมธอดสำหรับเซฟ state ลง Memento กับเมธอดสำหรับเรียกคืนค่าจาก Memento กลับใน originator

ต่อมาถ้าเราจะสร้าง CareTaker สำหรับเก็บ Memento

public class CareTaker {
    private List<Memento> mementoList = new ArrayList<Memento>();

    public void add(Memento state){
        mementoList.add(state);
    }

    public Memento get(int index){
        return mementoList.get(index);
    }
}

เพื่อที่จะให้เก็บ history เท่าไหร่ก็ได้เราจึงต้องสร้าง List ของ Memento เอาไว้ แล้วทุกครั้งที่มีการเปลี่ยนแปลงก็ขอ Memento แล้วก็เก็บลงใน List นี้

ต่อไปลองเอาไปใช้ดู

Originator originator = new Originator();
CareTaker careTaker = new CareTaker();
  
originator.setState("State #1");
originator.setState("State #2");
careTaker.add(originator.saveStateToMemento());
  
originator.setState("State #3");
careTaker.add(originator.saveStateToMemento());
  
originator.setState("State #4");
System.out.println("Current State: " + originator.getState());		
  
originator.getStateFromMemento(careTaker.get(0));
System.out.println("First saved State: " + originator.getState());
originator.getStateFromMemento(careTaker.get(1));
System.out.println("Second saved State: " + originator.getState());

===output===

Current State: State #4
First saved State: State #2
Second saved State: State #3

เวลาใช้เราจะต้องสร้าง instance ของ Originator กับ Caretaker แล้วหลังจากนั้นเมื่อมีการกำหนด state ให้ Originator ใหม่ หรือต้องการเซฟ state ปัจจุบัน ก็ขอ Memento จาก Originator แล้วส่งไปให้ Caretaker เก็บไว้ แล้วเมื่อไหร่ที่อยาก rollback ก็ขอ Memento จาก Caretaker แล้วเอาไปให้ Originator แทน

References

Memento pattern - Wikipedia

Memento Design Patter - SourceMakingn

Design Patterns - Momento Pattern - TutorialsPoint

#‎day63 #365วันแห่งโปรแกรม ‪#‎โครงการ365วันแห่ง‬...