Définition et structure
Le mode Memento est également appelé mode token. GOF définit le mode mémo comme: sans détruire l'encapsulation, capturez l'état interne d'un objet et sauvez cet état en dehors de l'objet. De cette façon, l'objet peut être restauré à son état enregistré d'origine plus tard.
Lorsque vous parlez du mode de commande, nous avons mentionné une fois que l'utilisation du rôle de commande intermédiaire peut réaliser les fonctions d'annulation et de refonte. D'après la définition, nous pouvons voir que le mode mémo est spécifiquement utilisé pour stocker l'état historique de l'objet, qui est d'une grande aide pour mettre en œuvre des fonctions d'annulation et de refaire. Par conséquent, en mode commande, les fonctions d'annulation et de rétablissement peuvent être implémentées en conjonction avec le mode mémo.
En fait, il est toujours très simple de simplement réaliser la fonction de sauvegarder l'état d'un objet à un certain moment - mettez les attributs à enregistrer dans l'objet dans un objet spécialisé dans la gestion de sauvegarde et appelez la méthode convenue pour remettre les attributs de sauvegarde dans l'objet d'origine en cas de besoin. Mais vous devez bien examiner pour permettre à votre objet de sauvegarde d'accéder aux propriétés de l'objet d'origine, cela signifie-t-il que vous devez divulguer toutes les propriétés des privés d'origine de l'objet dans le package? Si votre approche a cassé l'encapsulation, vous devriez envisager de refactoriser.
Le mode de mémorandum n'est qu'une solution générale proposée par GOF pour la question de "récupérer l'état d'origine d'un objet à un certain moment". Par conséquent, en termes de façon de maintenir l'encapsulation - en raison de facteurs tels que les caractéristiques du langage, le modèle de mémorandum n'est pas décrit en détail, mais explique uniquement les idées basées sur C ++.
1) Rôle du souvenir: Le rôle de mémorandum stocke le statut interne du "rôle d'initiateur du mémorandum". Le «rôle d'initiateur du mémorandum» détermine quels états internes du «rôle d'initiateur du mémorandum» sont stockés au besoin. Pour empêcher d'autres objets autres que le "rôle d'initiateur de mémorandum" d'accéder aux mémos. Les mémos ont en fait deux interfaces. Le "Rôle du gestionnaire de mémo" ne peut voir que l'interface étroite fournie par la note - elle est invisible pour les attributs stockés dans le rôle de mémo. Le "rôle d'initiateur du mémorandum" peut voir une interface large - vous pouvez obtenir les attributs que vous mettez dans le rôle de mémorandum.
2) Rôle de l'initiation de la note (initiateur): le "rôle d'initiation de la note" crée une note pour enregistrer son état interne au moment actuel. Utilisez des mémos pour restaurer l'état interne en cas de besoin.
3) Rôle du gestionnaire de mémorandum (gardien): responsable de la sauvegarde des mémos. Le contenu de la note ne peut pas être utilisé ou vérifié.
Le diagramme de classe du mode mémo est vraiment simple:
Implémentation du code général
Class Originator {private String State = ""; public String getState () {return State; } public void setState (String State) {this.state = state; } public memento createMmento () {return new memento (this.state); } public void restoreMmento (memento memento) {this.setState (memento.getState ()); }} classe 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 getMmento () {return memento; } public void setMemento (memento memento) {this.Mento = memento; }} public class Client {public static void main (String [] args) {originator originator = new Originator (); Originator.SetState ("Status 1"); System.out.println ("État initial:" + Originator.getState ()); Gardien de gardien = nouveau gardien (); caretaker.setMemento (originateur.CreateMmento ()); Originator.SetState ("Status2"); System.out.println ("Statut après avoir changé:" + Originator.GetState ()); originateur.restoreMmento (caretaker.getMemmento ()); System.out.println ("Statut après la récupération:" + Originator.getState ()); }}Le code démontre un exemple de sauvegarde unique à l'état unique. La logique est très simple: la variable d'état dans la classe d'origine doit être sauvegardée afin qu'elle puisse être restaurée en cas de besoin; Dans la classe de memento, il existe également une variable d'état utilisée pour stocker l'état temporaire de la variable d'état dans la classe d'origine; Et la classe Gardetaker est utilisée pour gérer la classe de mémorandum, qui est utilisée pour écrire des états ou récupérer des états dans l'objet de mémorandum.
Mémo multi-états multiples
Dans l'exemple de la démonstration du code général, la classe d'origine n'a qu'une seule variable d'état qui doit être sauvegardée, tandis que généralement, le rôle d'initiateur est généralement un JavaBean, il existe plus d'une variable qui doit être sauvegardée dans l'objet et plus d'un état qui doit être sauvegardé. Il s'agit d'une note multi-états multiple-backup. Il existe de nombreuses façons de mettre en œuvre des mémos. Il existe de nombreuses déformations et méthodes de traitement pour les mémos. Des méthodes comme le code général ne sont généralement pas utilisées. Dans la plupart des cas, les mémos sont des sauvegardes multiples et multiples. En fait, il est également très simple d'implémenter plusieurs états et multiples-dos. La méthode la plus couramment utilisée consiste à ajouter un conteneur de carte à Memento pour stocker tous les états et à utiliser un conteneur de carte dans la classe du gardien pour stocker toutes les sauvegardes. Ci-dessous, nous donnons un exemple de multi-États et de multi-backup:
Class Originator {private String State1 = ""; String privé State2 = ""; String privé 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 CreateMmento () {return new memento (beanutils.backupprop (this)); } public void restoremento (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, objet> map) {this.statemap = map; } public map <string, objet> 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> (); essayez {beanInfo beaninfo = introspector.getBeanInfo (bean.getClass ()); PropertyDescriptor [] Descriptors = beanInfo.getPropertyDescriptors (); pour (propriétéDescriptor des: descripteurs) {String fieldName = des.getName (); Méthode getter = des.getReadMethod (); Objet FieldValue = getter.invoke (bean, nouvel objet [] {}); if (! fieldName.EqualSignoreCase ("class")) {result.put (fieldName, fieldValue); }}}} catch (exception e) {e.printStackTrace (); } Retour Résultat; } public static void restoreprop (objet bean, map <string, object> propMap) {try {beaninfo beaninfo = introspector.getBeanInfo (bean.getClass ()); PropertyDescriptor [] Descriptors = beanInfo.getPropertyDescriptors (); pour (propriétéDescriptor des: descripteurs) {String fieldName = des.getName (); if (propMap.ContainsKey (fieldName)) {Method seter = des.getWriteMethod (); seter.invoke (bean, nouvel objet [] {propMap.get (fieldName)}); }}} catch (exception e) {e.printStackTrace (); }}} class Caretaker {Private Map <String, memento> memMap = new HashMap <String, memento> (); public memento getMmento (String index) {return memmap.get (index); } public void setMemento (String index, memento memento) {this.memmap.put (index, memento); }} classe Client {public static void main (String [] args) {Originator ori = new Originator (); Gardien de gardien = nouveau gardien (); ori.setstate1 ("Chine"); ori.setstate2 ("fort"); ori.setstate3 ("prospérité"); System.out.println ("=== Statut d'initialisation === / n" + ori); caretaker.setMemento ("001", ori.createMmento ()); ori.setstate1 ("logiciel"); ori.setstate2 ("structure"); ori.setstate3 ("excellent"); System.out.println ("=== État modifié === / n" + ori); ori.restoreMmento (caretaker.getMmento ("001")); System.out.println ("=== Status restauré === / n" + ori); }} Les avantages et les inconvénients du mode de mémorandum et les avantages du mode mémorandum pour les scénarios applicables sont:
Lorsque le statut dans le rôle de l'initiateur change, il peut s'agir d'un mauvais changement. Nous pouvons restaurer ce mauvais changement en utilisant le mode mémo.
Le statut de la sauvegarde est enregistré en dehors du rôle d'initiateur, donc le rôle de l'initiateur n'a pas besoin de gérer le statut de chaque sauvegarde.
Inconvénients du mode mémo:
Dans les applications réelles, le mode de mémorandum est multi-États et multi-backup. L'état du rôle d'initiateur doit être stocké dans l'objet de mémorandum, qui consomme des ressources relativement sévèrement.
Si vous avez besoin de fournir des opérations en arrière, l'utilisation du mode Mémo est très appropriée, comme les opérations de transaction JDBC, la récupération Ctrl + Z des éditeurs de texte, etc.