23種類のデザインモード(18)Javaメモモード


23種類のデザインモデル18編:JAVA覚書モード
定義:パッケージ性を破壊しないで一つのオブジェクトの内部状態をキャプチャし、そのオブジェクト以外にこの状態を保存する。このようにして、オブジェクトを元の状態に戻すことができます。
タイプ:行動類
クラス図:

私たちはプログラミングする時、常にオブジェクトの中間状態を保存します。必要に応じて、この状態に回復できます。例えば、Eclipseを使ってプログラムを作成する時、もしエラー(例えば、誤って何行かのコードを削除しました)を作成したら、削除前の状態に戻りたいです。Ctrl+Zを使って戻ります。この時、私たちはメモモードを使って実現できます。
メモモードの構成
発起人:現在時刻の内部状態を記録し、どれがバックアップ範囲に属するかを定義し、覚書データの作成と復旧を担当する。
メモ:発起人オブジェクトの内部状態を記憶し、必要なときに発起人が必要とする内部状態を提供する。
管理役:メモを管理し、メモを保存して提供します。
汎用コード実現

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類のstate変数はバックアップが必要です。必要な時に回復します。Mementoクラスには、Originatorクラスのstate変数を格納するためのstate変数もあります。Cartaker類は覚書類を管理し、覚書対象に状態を書き込み、または状態を取り戻すために用いられます。
マルチバックアップメモ
       汎用コードデモンストレーションの例では、Originator類は一つのstate変数だけがバックアップを必要としますが、通常は発起人キャラは一つのjavaBeanで、対象の中でバックアップが必要な変数は一つだけではなく、バックアップが必要な状態も一つだけではなく、これは複数の状態の覚書です。
        覚書を実現する方法はいろいろありますが、メモモードには多くの変形や処理があります。一般コードのような方式は一般的に使われません。実際には、多状態の多バックアップを実現するのも簡単です。最も一般的な方法は、MementooにMap容器を追加して、すべての状態を格納します。Cartaker類でも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("===     ===
"+ori); caretaker.setMemento("001",ori.createMemento()); ori.setState1(" "); ori.setState2(" "); ori.setState3(" "); System.out.println("=== ===
"+ori); ori.restoreMemento(caretaker.getMemento("001")); System.out.println("=== ===
"+ori); } }
メモモードの長所と短所と適用シーン
メモモードの利点は:
        発起人のキャラの状態が変わったら、これは間違った変化かもしれません。メモモードを使って、このエラーを元に戻すことができます。
        バックアップの状態は発起人キャラ以外に保存されていますので、発起人キャラは各バックアップの状態を管理する必要がありません。
メモモードの欠点は:
        実際のアプリケーションでは、メモモードは多状態であり、多バックアップであり、発起人の役割の状態はメモオブジェクトに記憶される必要があり、リソースの消費はより深刻である。
        ロールバック操作を提供する必要があるなら、メモモードを使うのはとても適しています。例えば、jdbcの事務操作、テキストエディタのCtrl+Z回復などです。
以上が本文の全部です。皆さんの勉強に役に立つように、私たちを応援してください。