2016-06-04 3 views
3

메멘토 패턴 (스킵 된 게터 및 세터)의 일반적인 구현 예입니다.메멘토 패턴 단점

public class Employee { 
    private String name; 
    private String phone; 

    public EmployeeMemento save() { 
     return new EmployeeMemento(name, phone); 
    } 

    public void revert(EmployeeMemento memento) { 
     this.name = memento.getName(); 
     this.phone = memento.getPhone(); 
    } 
} 


    public class EmployeeMemento { 
     private final String name; 
     private final String phone; 

     public EmployeeMemento(String name, String phone) { 
      this.name = name; 
      this.phone = phone; 
     } 
    } 

public class Caretaker { 
    private Stack<EmployeeMemento> history; 

    public Caretaker() { 
     history = new Stack<>(); 
    } 

    public void save(Employee employee) { 
     history.push(employee.save()); 
    } 

    public void revert(Employee employee) { 
     employee.revert(history.pop()); 
    } 
} 

발견 된이 패턴의 모든 구현은 위의 것과 거의 동일합니다. 그러나 구현이 종류에 대한 몇 가지 문제는 내가 좋아하는하지 않는 것이있다 :

  1. 그것은 employee.revert()caretaker.revert(employee) 모두 triger 가능합니다. 나는 오직 하나의 액세스 포인트를 원한다.
  2. EmployeeMemento를 변경하려면 Employee 클래스에서 변경해야합니다 (revert 메서드이기 때문에).

이 문제를 극복 할 방법이 있습니까? 어쩌면 너무 많은 관심을 기울일 수 있습니다.이 세부 사항은 그리 중요하지 않습니다.

답변

4

1) 케어 테이커는 메멘 티스를 돌보고 있어야하며 반드시 실행 취소/다시하기를 돌보아야하지 않습니다. 인터넷에서 다양한 구현 (예 : here)을 보면 Caretaker에는 revert()이 없지만 일반적으로 getMemento()과 같은 것을 볼 수 있습니다. 따라서 Undoing을 처리하는 클래스는 Caretaker에서 getMemento()을 호출 한 다음 Subject에서 revert()을 호출하는 다른 사람입니다.

케어 테이커가 실행 취소를 처리하기를 원한다해도 employee.revert()caretaker.revert()이 단독으로 사용하는 방법입니다.이 디자인에서는 다른 누구도 메멘토스에 액세스 할 수 없기 때문입니다. Caretaker 만 볼 수 있도록 가시성을 줄일 수 있습니다. (이 C++ 있었다면, 그것은 쉽게 friend의 사용에 의해 수행하지만, 자바에서 당신이 창조하고 package 가시성 또는 다른 방법을 사용해야 할 것입니다.)

2) 메멘토 패턴에서는 클래스와 그 유품은 단단히 결합. 사실 메멘토의 내부에 액세스 할 수있는 클래스 자체 일 뿐이며 메멘토가 어떻게 구성되는지는 누구도 알아야합니다. 따라서 클래스에 대한 변경이 메멘토로 전파되면 중요하지 않습니다.

다시 변경 사항을 분리하려는 경우 다시 창조적 일 수 있습니다. 예를 들어, namephone을 Class와 Memento에서 모두 복제하는 대신이 필드가 포함 된 다른 클래스 (예 : State)를 추출한 다음 원래 클래스와 Memento에 모두 State을 사용할 수 있습니다. 이 방법으로 클래스의 상태가 변경되면 State 만 수정하면됩니다.

사이드 노트 : Memento를 Subject 내부에 중첩 된 정적 클래스로 정의하는 것이 좋습니다.

public class Employee { 
    private State state; 

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

    public void revert(Memento memento) { 
     this.state = memento.state; 
    } 

    public static class Memento { 
     private final State state; 

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

    public static class State { 
     private String name; 
     private String phone; 
    } 
} 

public class Caretaker { 
    private Stack<Employee.Memento> history; 

    public Caretaker() { 
     history = new Stack<>(); 
    } 

    public void addMemento(Employee.Memento memento) { 
     history.push(memento); 
    } 

    public Employee.Memento getMemento() { 
     return history.pop(); 
    } 
} 

public class UndoHandler { 
    Employee employee; 
    Caretaker caretaker; 

    public void snapshot() { 
     caretaker.save(employee.save()); 
    } 

    public void undo() { 
     employee.revert(caretaker.getMemento()); 
    } 
} 
:

그래서 당신의 문제를 해결 내 디자인은이 같은 것