Heim  >  Artikel  >  Java  >  Detaillierte Erläuterung der Verwendung des Memo-Musters im Java-Entwurfsmuster

Detaillierte Erläuterung der Verwendung des Memo-Musters im Java-Entwurfsmuster

高洛峰
高洛峰Original
2017-01-19 15:42:35985Durchsuche

Definition und Struktur

Der Memento-Modus wird auch Token-Modus genannt. GOF definiert das Memo-Muster als: Erfassen des internen Zustands eines Objekts und Speichern dieses Zustands außerhalb des Objekts, ohne die Kapselung zu zerstören. Dadurch können Sie das Objekt später wieder in seinen ursprünglich gespeicherten Zustand versetzen.

Als wir über den Befehlsmodus sprachen, haben wir einmal erwähnt, dass die Funktionen „Rückgängig“ und „Wiederherstellen“ durch die Verwendung der Befehlsrolle in der Mitte realisiert werden können. Aus der Definition geht hervor, dass der Memo-Modus speziell zum Speichern des historischen Status von Objekten verwendet wird, was für die Realisierung der Rückgängig- und Wiederherstellungsfunktionen sehr hilfreich ist. Daher können im Befehlsmodus die Rückgängig- und Wiederherstellungsfunktionen in Verbindung mit dem Memo-Modus implementiert werden.

Tatsächlich ist es sehr einfach, die Funktion zum Speichern des Zustands eines Objekts zu einem bestimmten Zeitpunkt zu realisieren: Legen Sie die im Objekt zu speichernden Attribute in ein speziell für die Sicherung verwaltetes Objekt ab und rufen Sie es auf, wenn erforderlich Die vereinbarte Methode fügt die gesicherten Eigenschaften wieder in das ursprüngliche Objekt ein. Aber Sie müssen genauer hinschauen, damit Ihr Backup-Objekt auf die Eigenschaften des Originalobjekts zugreifen kann. Bedeutet das, dass Sie alle ursprünglichen privaten Eigenschaften des Objekts offenlegen müssen oder die ursprünglichen privaten Eigenschaften des Objekts offenlegen müssen? im Paket? Wenn Ihr Ansatz die Kapselung beschädigt hat, sollten Sie eine Umgestaltung in Betracht ziehen.

Der Memo-Modus ist lediglich eine von GOF vorgeschlagene allgemeine Lösung für das Problem der „Wiederherstellung des ursprünglichen Zustands eines Objekts zu einem bestimmten Zeitpunkt“. Daher wird der Memo-Modus aufgrund des Einflusses von Sprachmerkmalen und anderen Faktoren nicht im Detail beschrieben, sondern nur auf der auf C++ basierenden Idee näher erläutert.


 1) Memento-Rolle: Die Memento-Rolle speichert den internen Zustand der „Memento-initiierenden Rolle“. Die „Memo-Initiator-Rolle“ legt fest, welche internen Zustände der „Memo-Initiator-Rolle“ die Memo-Rolle bei Bedarf speichert. Um zu verhindern, dass andere Objekte als die „Memo-initiierende Rolle“ auf das Memo zugreifen. Memo verfügt tatsächlich über zwei Schnittstellen. Die „Memo-Manager-Rolle“ kann nur die von Memo bereitgestellte schmale Schnittstelle sehen – die in der Memo-Rolle gespeicherten Eigenschaften sind nicht sichtbar. Die „Memo-initiierende Rolle“ kann eine breite Schnittstelle sehen – sie kann die Attribute abrufen, die sie in die Memo-Rolle einfügt.

2) Memo-Ersteller-Rolle: Die „Memo-Ersteller-Rolle“ erstellt ein Memo, um seinen internen Status zum aktuellen Zeitpunkt aufzuzeichnen. Verwenden Sie Memos, um bei Bedarf den internen Zustand wiederherzustellen.

 3) Hausmeisterrolle: Verantwortlich für die Aufbewahrung guter Notizen. Der Inhalt des Memos kann nicht bearbeitet oder eingesehen werden.

Das Klassendiagramm des Memo-Modus könnte nicht einfacher sein:

Detaillierte Erläuterung der Verwendung des Memo-Musters im Java-Entwurfsmuster

Allgemeine Code-Implementierung

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());
  }
}

Der Code zeigt ein Beispiel für einen einzelnen Status und eine einzelne Sicherung. Die Logik ist sehr einfach: Die Statusvariable in der Originator-Klasse muss gesichert werden, damit sie bei Bedarf in der Memento-Klasse wiederhergestellt werden kann Es gibt auch eine Statusvariable, die zum Speichern der Statusvariablen in der Klasse verwendet wird, um die Memo-Klasse zu verwalten und um den Status in das Memo-Objekt zu schreiben oder daraus abzurufen.

Multi-State und mehrere Backup-Memos
Im Beispiel der allgemeinen Code-Demonstration verfügt die Originator-Klasse nur über eine Statusvariable, die gesichert werden muss. Unter normalen Umständen ist die Originator-Rolle normalerweise eine javaBean, und es gibt mehr als eine Variable im Objekt, die gesichert werden muss. Eine, und es gibt mehr als einen Status, der gesichert werden muss. Dies ist ein Multi-State-Multi-Backup-Memo. Es gibt viele Möglichkeiten, Memos zu implementieren. Methoden wie allgemeiner Code werden im Allgemeinen nicht verwendet. Tatsächlich ist es sehr einfach, mehrere Zustände und mehrere Sicherungen zu implementieren. Die gebräuchlichste Methode besteht darin, Memento einen Kartencontainer hinzuzufügen, um alle Zustände zu speichern, und außerdem einen Kartencontainer in der Caretaker-Klasse zu verwenden, um alle Sicherungen zu speichern. Nachfolgend geben wir ein Beispiel für ein Multi-State-Multi-Backup:

 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);
  }
}

Vorteile, Nachteile und anwendbare Szenarien des Memo-Modus
Die Vorteile von Memo Modus sind:
Wenn sich der Status in der Initiatorrolle ändert, handelt es sich möglicherweise um eine falsche Änderung. Wir können den Memomodus verwenden, um diese falsche Änderung wiederherzustellen.
Der Status des Backups wird außerhalb der Initiatorrolle gespeichert, sodass die Initiatorrolle nicht den Status jedes Backups verwalten muss.
Nachteile des Memo-Modus:
In praktischen Anwendungen ist der Memo-Modus Multi-State und Multi-Backup. Der Status der Initiatorrolle muss im Memo-Objekt gespeichert werden, was erhebliche Ressourcen verbraucht.
Wenn Rollback-Vorgänge bereitgestellt werden müssen, eignet sich der Memo-Modus sehr gut, z. B. JDBC-Transaktionsvorgänge, Texteditor-Strg + Z-Wiederherstellung usw.

Ausführlichere Artikel zur Verwendung des Memo-Musters in Java-Designmustern finden Sie auf der chinesischen PHP-Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn