정의 및 구조
메멘토 모드는 토큰 모드라고도 합니다. GOF는 메모 패턴을 다음과 같이 정의합니다. 객체의 내부 상태를 캡처하고 캡슐화를 파괴하지 않고 이 상태를 객체 외부에 저장합니다. 이렇게 하면 나중에 개체를 원래 저장된 상태로 복원할 수 있습니다.
명령 모드를 이야기할 때, 중간에 명령 역할을 사용하면 실행 취소 및 다시 실행 기능을 구현할 수 있다고 언급한 적이 있습니다. 정의에서 알 수 있듯이 메모 모드는 개체의 기록 상태를 저장하는 데 특별히 사용되며 실행 취소 및 다시 실행 기능을 구현하는 데 매우 유용합니다. 따라서 명령 모드에서는 메모 모드와 연동하여 Undo, Redo 기능을 구현할 수 있다.
실제로 특정 시점의 객체 상태를 저장하는 기능을 구현하는 것은 매우 간단합니다. 객체에 저장할 속성을 백업을 위해 특별히 관리되는 객체에 넣고, 필요할 때 호출하면 됩니다. 필요 합의된 방법은 백업된 속성을 원래 개체에 다시 넣습니다. 하지만 좀 더 자세히 살펴봐야 합니다. 백업 개체가 원본 개체의 속성에 액세스할 수 있도록 하려면 개체의 원래 프라이빗 속성을 모두 노출해야 한다는 의미인가요, 아니면 개체의 원래 프라이빗 속성을 노출해야 한다는 뜻인가요? 패키지에? 접근 방식이 캡슐화를 깨뜨린 경우 리팩토링을 고려하세요.
메모 모드는 "특정 시간에 개체를 원래 상태로 복원"하는 문제에 대해 GOF에서 제안한 일반적인 솔루션일 뿐입니다. 따라서 캡슐화를 유지하는 방법에 대해서는 언어 특성이나 기타 요인의 영향으로 메모 모드에 대해서는 자세히 설명하지 않고 C++ 기반의 아이디어만 설명합니다.
1) 메멘토 역할: 메멘토 역할은 "메멘토 개시 역할"의 내부 상태를 저장합니다. "메모 시작 역할"은 메모 역할이 필요에 따라 저장하는 "메모 시작 역할"의 내부 상태를 결정합니다. "메모 개시 역할" 이외의 개체가 메모에 접근하는 것을 방지합니다. 메모에는 실제로 두 가지 인터페이스가 있습니다. "메모 관리자 역할"은 메모에서 제공하는 좁은 인터페이스만 볼 수 있습니다. 메모 역할에 저장된 속성은 표시되지 않습니다. "메모 시작 역할"은 광범위한 인터페이스를 볼 수 있습니다. 즉, 메모 역할에 추가하는 속성을 얻을 수 있습니다.
2) 메모 작성자 역할: "메모 작성자 역할"은 메모를 작성하여 현재 순간의 내부 상태를 기록합니다. 필요할 때 메모를 사용하여 내부 상태를 복원하세요.
3) 관리인 역할: 좋은 메모를 보관하는 역할. 메모 내용을 조작하거나 확인할 수 없습니다.
메모 모드의 클래스 다이어그램은 이보다 더 간단할 수 없습니다.
일반 코드 구현
class Originator { private String state = ""; public String getState() { return state; } public void setState(String state) { this.state = state; } public Memento createMemento(){ return new Memento(this.state); } public void restoreMemento(Memento memento){ this.setState(memento.getState()); } } class Memento { private String state = ""; public Memento(String state){ this.state = state; } public String getState() { return state; } public void setState(String state) { this.state = state; } } class Caretaker { private Memento memento; public Memento getMemento(){ return memento; } public void setMemento(Memento memento){ this.memento = memento; } } public class Client { public static void main(String[] args){ Originator originator = new Originator(); originator.setState("状态1"); System.out.println("初始状态:"+originator.getState()); Caretaker caretaker = new Caretaker(); caretaker.setMemento(originator.createMemento()); originator.setState("状态2"); System.out.println("改变后状态:"+originator.getState()); originator.restoreMemento(caretaker.getMemento()); System.out.println("恢复后状态:"+originator.getState()); } }
이 코드는 단일 상태 및 단일 백업의 예를 보여줍니다. 논리는 매우 간단합니다. 필요할 때 복원할 수 있도록 Originator 클래스의 상태 변수도 백업되어야 합니다. Originator 클래스에 상태 변수를 저장하는 데 사용되는 상태 변수 Caretaker 클래스는 메모 클래스를 관리하는 데 사용되며 메모 개체에 상태를 쓰거나 메모 개체에서 상태를 검색하는 데 사용됩니다.
다중 상태 및 다중 백업 메모
일반적인 코드 데모 예제에서 Originator 클래스에는 백업해야 하는 상태 변수가 하나만 있습니다. 일반적으로 개시자 역할은 javaBean입니다. 그리고 백업해야 할 개체에 변수가 두 개 이상 있고, 백업해야 할 상태가 두 개 이상 있습니다. 다중 상태 다중 백업 메모입니다. 메모를 구현하는 방법은 다양하며, 메모 패턴에는 다양한 변형과 처리 방법이 있으며 일반적으로 메모 패턴은 다중 상태 및 다중 백업과 같은 방법을 사용하지 않습니다. 실제로 다중 상태 및 다중 백업을 구현하는 것은 매우 간단합니다. 가장 일반적인 방법은 Memento에 Map 컨테이너를 추가하여 모든 상태를 저장하고 Caretaker 클래스의 Map 컨테이너를 사용하여 모든 백업을 저장하는 것입니다. 아래에서는 다중 상태 다중 백업의 예를 제공합니다.
class Originator { private String state1 = ""; private String state2 = ""; private String state3 = ""; public String getState1() { return state1; } public void setState1(String state1) { this.state1 = state1; } public String getState2() { return state2; } public void setState2(String state2) { this.state2 = state2; } public String getState3() { return state3; } public void setState3(String state3) { this.state3 = state3; } public Memento createMemento(){ return new Memento(BeanUtils.backupProp(this)); } public void restoreMemento(Memento memento){ BeanUtils.restoreProp(this, memento.getStateMap()); } public String toString(){ return "state1="+state1+"state2="+state2+"state3="+state3; } } class Memento { private Map<String, Object> stateMap; public Memento(Map<String, Object> map){ this.stateMap = map; } public Map<String, Object> getStateMap() { return stateMap; } public void setStateMap(Map<String, Object> stateMap) { this.stateMap = stateMap; } } class BeanUtils { public static Map<String, Object> backupProp(Object bean){ Map<String, Object> result = new HashMap<String, Object>(); try{ BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass()); PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors(); for(PropertyDescriptor des: descriptors){ String fieldName = des.getName(); Method getter = des.getReadMethod(); Object fieldValue = getter.invoke(bean, new Object[]{}); if(!fieldName.equalsIgnoreCase("class")){ result.put(fieldName, fieldValue); } } }catch(Exception e){ e.printStackTrace(); } return result; } public static void restoreProp(Object bean, Map<String, Object> propMap){ try { BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass()); PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors(); for(PropertyDescriptor des: descriptors){ String fieldName = des.getName(); if(propMap.containsKey(fieldName)){ Method setter = des.getWriteMethod(); setter.invoke(bean, new Object[]{propMap.get(fieldName)}); } } } catch (Exception e) { e.printStackTrace(); } } } class Caretaker { private Map<String, Memento> memMap = new HashMap<String, Memento>(); public Memento getMemento(String index){ return memMap.get(index); } public void setMemento(String index, Memento memento){ this.memMap.put(index, memento); } } class Client { public static void main(String[] args){ Originator ori = new Originator(); Caretaker caretaker = new Caretaker(); ori.setState1("中国"); ori.setState2("强盛"); ori.setState3("繁荣"); System.out.println("===初始化状态===\n"+ori); caretaker.setMemento("001",ori.createMemento()); ori.setState1("软件"); ori.setState2("架构"); ori.setState3("优秀"); System.out.println("===修改后状态===\n"+ori); ori.restoreMemento(caretaker.getMemento("001")); System.out.println("===恢复后状态===\n"+ori); } }
메모 모드의 장점, 단점 및 적용 시나리오
메모 모드의 장점
개시자 역할의 상태가 변경되면 잘못된 변경일 수 있으므로 메모 모드를 사용하여 잘못된 변경 사항을 복원할 수 있습니다.
백업 상태는 개시자 역할 외부에 저장되므로 개시자 역할은 각 백업의 상태를 관리할 필요가 없습니다.
메모 모드의 단점:
실제 애플리케이션에서 메모 모드는 다중 상태 및 다중 백업입니다. 개시자 역할의 상태는 메모 개체에 저장되어야 하며 이는 리소스를 심각하게 소모합니다.
롤백 작업을 제공해야 하는 경우 JDBC 트랜잭션 작업, 텍스트 편집기 Ctrl+Z 복구 등과 같은 메모 모드가 매우 적합합니다.
자바 디자인 패턴에서 메모 패턴 활용에 대한 자세한 글은 PHP 중국어 홈페이지를 참고해주세요!