Memento mönster

Mementomönstret är ett mjukvarudesignmönster som exponerar ett objekts privata interna tillstånd . Ett exempel på hur detta kan användas är att återställa ett objekt till dess tidigare tillstånd (ångra via återställning), ett annat är versionshantering, ett annat är anpassad serialisering.

Mementomönstret implementeras med tre objekt: upphovsmannen , en vaktmästare och ett minnesmärke . Upphovsmannen är något objekt som har ett internt tillstånd. Vaktmästaren ska göra något mot upphovsmannen, men vill kunna ångra förändringen. Vaktmästaren ber först upphovsmannen om ett minnesobjekt. Sedan gör den vilken operation (eller sekvens av operationer) den än skulle göra. För att återgå till tillståndet före operationerna, returnerar det minnesobjektet till upphovsmannen. Själva minnesobjektet är ett ogenomskinligt föremål (ett som vaktmästaren inte kan eller bör ändra). När du använder det här mönstret bör man vara försiktig om upphovsmannen kan ändra andra objekt eller resurser - minnesmönstret fungerar på ett enda objekt.

Klassiska exempel på mementomönstret inkluderar en pseudoslumptalsgenerator (varje konsument av PRNG fungerar som en vaktmästare som kan initiera PRNG (upphovsmannen) med samma frö (memento) för att producera en identisk sekvens av pseudoslumptal) och staten i en finita tillståndsmaskin.

Översikt

Mementos designmönster är ett av de tjugotre välkända GoF-designmönstren som beskriver hur man löser återkommande designproblem för att designa flexibel och återanvändbar objektorienterad programvara, det vill säga objekt som är lättare att implementera, ändra, testa och återanvändning. Memento-mönstret skapades av Noah Thompson, David Espiritu och Dr Drew Clinkenbeard för tidiga HP-produkter.

Vilka problem kan Mementos designmönster lösa?

  • Det interna tillståndet för ett objekt bör sparas externt så att objektet kan återställas till detta tillstånd senare.
  • Objektets inkapsling får inte kränkas.

Problemet är att ett väldesignat objekt är inkapslat så att dess representation (datastruktur) är dold inuti objektet och inte kan nås från utsidan av objektet.

Vilken lösning beskriver Mementos designmönster?

Gör ett objekt (upphovsman) själv ansvarigt för

  • spara dess interna tillstånd till ett (minnes)objekt och
  • återställa till ett tidigare tillstånd från ett (memento) objekt.

Endast upphovsmannen som skapade ett minne får åtkomst till det.

En klient (vaktmästare) kan begära ett minne från upphovsmannen (för att spara upphovsmannens interna tillstånd) och skicka ett minne tillbaka till upphovsmannen (för att återställa till ett tidigare tillstånd).

Detta gör det möjligt att spara och återställa det interna tillståndet för en upphovsman utan att bryta mot dess inkapsling.

Se även UML-klassen och sekvensdiagrammet nedan.

Strukturera

UML klass och sekvensdiagram

Ett exempel på UML-klass och sekvensdiagram för Memento-designmönstret.




I ovanstående UML-klassdiagram hänvisar Caretaker -klassen till Originator -klassen för att spara ( createMemento() ) och återställa ( restore(memento) ) upphovsmannens interna tillstånd. Klassen Originator implementerar (1) createMemento() genom att skapa och returnera ett Memento- objekt som lagrar upphovsmannens aktuella interna tillstånd och (2) restore(memento) genom att återställa tillståndet från det godkända Memento - objektet.



UML - sekvensdiagrammet visar körtidsinteraktionerna: (1) Sparar upphovsmannens interna tillstånd: Caretaker -objektet anropar createMemento() Originator- objektet, vilket skapar ett Memento- objekt, sparar dess nuvarande interna tillstånd ( setState() ), och returnerar minnet till vaktmästaren . _ (2) Återställa upphovsmannens interna tillstånd: Vaktmästaren anropar restore (memento) Originator- objektet och specificerar Memento- objektet som lagrar tillståndet som ska återställas. Upphovsmannen får tillståndet ( getState() ) från Memento för att ställa in sitt eget tillstånd .

Java exempel

Följande Java-program illustrerar "ångra" användningen av minnesmönstret.

 
 
  
      
    
    
 
        
          
          
    
 
       
        
          
    
 
        
          
          
    
 
        
           

           
              
        
 
        
           
             
        
    

 
  
         
            
 
            
        
        
        
        
        
        
        
 
           
    
 importera  java.util.List  ;  importera  java.util.ArrayList  ;  klass  Upphovsman  {  privat  strängtillstånd  ;  _  // Klassen kan också innehålla ytterligare data som inte är en del av  //  -tillståndet sparat i minnet..  public  void  set  (  String  state )   {  this  .  tillstånd  =  tillstånd  ;  System  .  ut  .  println  (  "Originator: Ange tillstånd till "  +  tillstånd  );  }  public  Memento  saveToMemento  ()  {  System  .  ut  .  println  (  "Upphov: Spara i minnet."  );  returnera  nytt  minne  (  detta  .tillstånd  )  ;  }  public  void  restoreFromMemento  (  Memento  memento  )  {  detta  .  tillstånd  =  memento  .  getSavedState  ();  System  .  ut  .  println  (  "Originator: Tillstånd efter återställning från Memento: "  +  tillstånd  );  }  public  static  class  Memento  {  private  final  String  state  ;  public  Memento  (  String  stateToSave  )  {  state  =  stateToSave  ;  }  // endast tillgänglig för yttre klass  privat  String  getSavedState  ()  {  return  state  ;  } }  }  class  Caretaker  {  public  static  void  main  (  String  [  ]  args  )  {  List  <  Originator  .  Memento  >  savedStates  =  new  ArrayList  <  Originator  .  Memento  >  ();  Upphovsman  upphovsman  =  ny  upphovsman  ();  upphovsman  .  set  (  "State1"  );  upphovsman  .  set  (  "State2"  );  sparade tillstånd  .  add  (  upphovsman  .  saveToMemento  ());  upphovsman  .  set  (  "State3"  );  // Vi kan begära flera minnen och välja vilket vi ska gå tillbaka till.  sparade tillstånd  .  add  (  upphovsman  .  saveToMemento  ());  upphovsman  .  set  (  "State4"  );  upphovsman  .  restoreFromMemento  (  savedStates  .  get  (  1  ));  }  } 

Utgången är:

Upphovsman: Inställning av tillstånd till tillstånd1 Upphovsman: Inställning av tillstånd till tillstånd2 Upphovsman: Sparar till minne. Upphovsman: Ställer in tillstånd till State3 Upphovsman: Sparar till Memento. Upphovsman: Ställer in tillstånd till State4 Originator: Tillstånd efter återställning från Memento: Tillstånd3

Det här exemplet använder en sträng som tillstånd, vilket är ett oföränderligt objekt i Java. I verkliga scenarier kommer staten nästan alltid att vara ett föränderligt objekt, i vilket fall en kopia av staten måste göras.

Det måste sägas att den visade implementeringen har en nackdel: den deklarerar en intern klass. Det skulle vara bättre om denna minnesstrategi kunde tillämpas på mer än en upphovsman.

Det finns huvudsakligen tre andra sätt att uppnå Memento:

  1. Serialisering.
  2. En klass som deklareras i samma paket.
  3. Objektet kan också nås via en proxy, som kan uppnå valfri spara/återställningsoperation på objektet.

C# exempel

Mementomönstret tillåter en att fånga det interna tillståndet av ett objekt utan att bryta inkapslingen så att man senare kan ångra/återställa ändringarna om så krävs. Här kan man se att mementoobjektet faktiskt används för att återställa de ändringar som gjorts i objektet.

 

       

      
    
          
    

      
    
          
        
        

           
        
              
              
        

          
        
            
              
        

           
        
              
              
        
    


 

       
    
            

            
        
        
        
        
        
        
        

        
    
 class  Memento  {  privat  skrivskyddad  sträng  savedState  ;  privat  Memento  (  sträng  stateToSave  )  {  savedState  =  stateToSave  ;  }  public  class  Originator  {  privat  strängtillstånd  ;  _  // Klassen kan också innehålla ytterligare data som inte är en del av  //-tillståndet sparat i minnet.  public  void  Set  (  strängtillstånd  )  {  Console  .  _  WriteLine  (  "Originator: Ange tillstånd till "  +  tillstånd  );  detta  .  tillstånd  =  tillstånd  ;  }  public  Memento  SaveToMemento  ()  {  Console  .  WriteLine  (  "Originator: Saving to Memento." )  ;  returnera  nytt  Memento  (  tillstånd  );  }  public  void  RestoreFromMemento  (  Memento  memento  )  {  state  =  memento  .  savedState  ;  Konsol  .  WriteLine  (  "Originator: Status efter återställning från Memento: "  +  state  );  } }  }  class  Caretaker  {  static  void  Main  (  string  [  ]  args  )  {  var  savedStates  =  new  List  <  Memento  >();  var  originator  =  nytt  minne  .  Upphovsman  ();  upphovsman  .  Set  (  "State1"  );  upphovsman  .  Set  (  "State2"  );  sparade tillstånd  .  Lägg till  (  upphovsman  .  SaveToMemento  ());  upphovsman  .  Set  (  "State3"  );  // Vi kan begära flera minnen och välja vilket vi ska gå tillbaka till.  sparade tillstånd  .  Lägg till  (  upphovsman  .  SaveToMemento  ());  upphovsman  .  Set  (  "State4"  );  upphovsman  .  RestoreFromMemento  (  savedStates  [  1  ]);  }  } 

Python exempel






 
        
          

     
         


 
      

        
         
          

       
        
         

        
          
         


  
  









 """  Memento mönster exempel.  """  klass  Memento  :  def  __init__  (  self  ,  state  )  ->  None  :  self  .  _state  =  state  def  get_saved_state  (  själv  ):  returnera  själv  .  _state  class  Originator  :  _state  =  ""  def  set  (  self  ,  state  )  ->  None  :  print  (  "Originator: Setting state to"  ,  state  )  self  .  _state  =  state  def  save_to_memento  (  self  )  ->  Memento  :  print  (  "Originator: Saving to Memento."  )  return  Memento  (  self  .  _state  )  def  restore_from_memento  (  self  ,  memento  )  ->  None  :  self  .  _state  =  memento  .  get_saved_state  ()  print  (  "Originator: Status efter återställning från Memento:"  ,  self  .  _state  )  saved_states  =  []  originator  =  Upphovsman  ()  upphovsman  .  set  (  "State1"  )  upphovsman  .  set  (  "State2"  )  saved_states  .  append  (  upphovsman  .  save_to_memento  ())  upphovsman  .  set  (  "State3"  )  saved_states  .  append  (  upphovsman  .  save_to_memento  ())  upphovsman  .  set  (  "State4"  )  upphovsman  .  restore_from_memento  (  sparade_tillstånd  [  1  ]) 

Javascript exempel



   
       

        
          
    

        
         
    




   
           

        
            
             
                   
            
        
            
              
        
    




   
           
            
            
        
            
             
        
    

    
    


  

   


  
 
   


0
   



    // Mementomönstret används för att spara och återställa tillståndet för ett objekt.  // Ett minne är en ögonblicksbild av ett objekts tillstånd.  var  Memento  =  {  // Namnområde: Memento  savedState  :  null  ,  // Det sparade tillståndet för objektet.  save  :  function  (  state  )  {  // Spara ett objekts tillstånd.  detta  .  savedState  =  tillstånd  ;  },  restore  :  function  ()  {  // Återställ tillståndet för ett objekt.  lämna tillbaka  detta  .  savedState  ;  }  };  // Upphovsmannen är objektet som skapar minnet.  // definierar en metod för att spara tillståndet i ett minne.  var  Originator  =  {  // Namnområde: Originator  state  :  null  ,  // Status som ska lagras  // Skapar en ny originator med initialtillståndet null  createMemento  :  function  ()  {  return  {  state  :  this  .  tillstånd  // Tillståndet kopieras till minnet.  };  },  setMemento  :  function  (  memento  )  {  // Ställer in tillståndet för upphovsmannen från ett minne  till detta  .  tillstånd  =  memento  .  tillstånd  ;  }  };  // Vaktmästaren lagrar minnen av objekten och  // tillhandahåller operationer för att hämta dem.  var  Caretaker  =  {  // Namnområde: Caretaker-  minnen  :  [],  // Minnen av objekten.  addMemento  :  function  (  memento  )  {  // Lägg till ett minne till samlingen.  detta  .  minnen  .  push  (  minne  );  },  getMemento  :  function  (  index  )  {  // Få ett minne från samlingen.  lämna tillbaka  detta  .  minnen  [  index  ];  }  };  var  action_step  =  "Foo"  ;  // Åtgärden som ska utföras/objekttillståndet som ska lagras.  var  action_step_2  =  "Bar"  ;  // Åtgärden som ska utföras/objekttillståndet som ska lagras.  // ställ in initialtillståndet  Originator  .  state  =  action_step  ;  Vaktmästare  .  addMemento  (  upphovsman  .  createMemento  ());  // spara tillståndet till  historikkonsolen  .  log  (  "Initial State: "  +  Originator  .  state  );  // Foo  // ändra tillståndet  Originator  .  state  =  action_step_2  ;  Vaktmästare  .  addMemento  (  upphovsman  .  createMemento  ());  // spara tillståndet till  historikkonsolen  .  log  (  "Tillstånd efter ändring: "  +  Upphovsman  .  tillstånd  );  // Bar  // återställ den första tillståndet - ångra  Originator  .  setMemento  (  Vaktmästare  .  getMemento  (  ));  konsol  .  log  (  "Tillstånd efter ångra: "  +  Upphovsman  .  tillstånd  );  // Foo  // återställ det andra tillståndet - gör om  Originator  .  setMemento  (  vaktmästare  .  getMemento  (  1  ));  konsol  .  log  (  "State After Redo: "  +  Originator  .  state  );  // Bar 

externa länkar

  • Beskrivning av Memento Pattern i Ada
  • Memento UML Class Diagram med C#- och .NET-kodexempel
  • Självstudie för SourceMaking
  • Memento Design Pattern med Java