Maison > Java > javaDidacticiel > Explication détaillée de l'utilisation du modèle de mémo dans le modèle de conception Java

Explication détaillée de l'utilisation du modèle de mémo dans le modèle de conception Java

高洛峰
Libérer: 2017-01-19 15:42:35
original
1023 Les gens l'ont consulté

Définition et structure

Le mode Memento est également appelé mode Token. GOF définit le modèle de mémo comme : capturer l'état interne d'un objet et enregistrer cet état en dehors de l'objet sans détruire l'encapsulation. Cela vous permet de restaurer ultérieurement l'objet à son état d'origine enregistré.

En parlant du mode commande, nous avons mentionné un jour que les fonctions d'annulation et de rétablissement peuvent être réalisées en utilisant le rôle de commande au milieu. Il ressort de la définition que le mode mémo est spécialement utilisé pour stocker l'état historique des objets, ce qui est très utile pour réaliser les fonctions d'annulation et de rétablissement. Par conséquent, en mode commande, les fonctions d'annulation et de rétablissement peuvent être implémentées conjointement avec le mode mémo.

En fait, il est très simple de réaliser la fonction de sauvegarde de l'état d'un objet à un certain moment - mettre les attributs à sauvegarder dans l'objet dans un objet spécialement géré pour la sauvegarde, et l'appeler quand nécessaire La méthode convenue remet les propriétés sauvegardées dans l'objet d'origine. Mais vous devez y regarder de plus près. Afin de permettre à votre objet de sauvegarde d'accéder aux propriétés de l'objet d'origine, cela signifie-t-il que vous devez exposer toutes les propriétés privées d'origine de l'objet ou exposer les propriétés privées d'origine de l'objet. dans le colis ? Si votre approche a rompu l’encapsulation, envisagez de la refactoriser.

Le mode mémo n'est qu'une solution générale proposée par GOF au problème de la "restauration de l'état d'origine d'un objet à un certain moment". Par conséquent, sur la façon de maintenir l'encapsulation - en raison de l'influence des caractéristiques du langage et d'autres facteurs, le mode mémo n'est pas décrit en détail, mais développe uniquement l'idée basée sur C.


 1) Rôle Memento : Le rôle Memento stocke l'état interne du "rôle initiateur de mémento". Le « rôle initiateur de mémo » détermine quels états internes du « rôle initiateur de mémo » le rôle mémo stocke selon les besoins. Pour empêcher des objets autres que le "rôle initiateur de mémo" d'accéder au mémo. Memo a en fait deux interfaces. Le "rôle Memo Manager" ne peut voir que l'interface étroite fournie par Memo - les propriétés stockées dans le rôle Memo ne sont pas visibles. Le "rôle initiateur de mémo" peut voir une large interface - il peut obtenir les attributs qu'il met dans le rôle de mémo.

2) Rôle Memo Originator : Le "Memo Originator role" crée un mémo pour enregistrer son statut interne au moment actuel. Utilisez des mémos pour restaurer l'état interne en cas de besoin.

 3) Rôle de gardien : Responsable de conserver les bons mémos. Le contenu du mémo ne peut pas être utilisé ou inspecté.

Le diagramme de classes du mode mémo ne pourrait pas être plus simple :

Explication détaillée de lutilisation du modèle de mémo dans le modèle de conception Java

Implémentation générale du code

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());
  }
}
Copier après la connexion

Le code montre un exemple d'état unique et de sauvegarde unique. La logique est très simple : la variable d'état dans la classe Originator doit être sauvegardée afin qu'elle puisse être restaurée en cas de besoin dans la classe Memento ; , il existe également une variable d'état utilisée pour stocker l'expéditeur. L'état temporaire de la variable d'état dans la classe est utilisé pour gérer la classe mémo et est utilisé pour écrire l'état ou récupérer l'état de l'objet mémo.

Mémos de sauvegarde multi-états et multiples
Dans l'exemple de démonstration de code courant, la classe Originator n'a qu'une seule variable d'état qui doit être sauvegardée. Dans des circonstances normales, le rôle d'initiateur est généralement un javaBean, et il y a plus d'une variable dans l'objet qui doit être sauvegardée. Une, et il y a plus d'un état qui doit être sauvegardé. Il s'agit d'un mémo multi-sauvegarde multi-états. Il existe de nombreuses façons d'implémenter les mémos. Le modèle de mémo présente de nombreuses variantes et les méthodes de traitement telles que le code général ne sont généralement pas utilisées. Dans la plupart des cas, le modèle de mémo est multi-états et multi-sauvegarde. En fait, il est très simple d'implémenter des sauvegardes multi-états et multiples. La méthode la plus courante consiste à ajouter un conteneur Map à Memento pour stocker tous les états, et à utiliser également un conteneur Map dans la classe Caretaker pour stocker toutes les sauvegardes. Ci-dessous, nous donnons un exemple de sauvegarde multi-états :

 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);
  }
}
Copier après la connexion

Avantages, inconvénients et scénarios applicables du mode Mémo
Les avantages du mode Mémo Les modes sont :
Lorsque le statut du rôle d'initiateur change, il peut s'agir d'un mauvais changement. Nous pouvons utiliser le mode mémo pour restaurer ce mauvais changement.
Le statut de la sauvegarde est enregistré en dehors du rôle initiateur, le rôle initiateur n'a donc pas besoin de gérer le statut de chaque sauvegarde.
Inconvénients du mode mémo :
Dans les applications pratiques, le mode mémo est multi-états et multi-sauvegarde. Le statut du rôle initiateur doit être stocké dans l'objet mémo, ce qui consomme beaucoup de ressources.
S'il est nécessaire de fournir des opérations de restauration, le mode mémo est très approprié, comme les opérations de transaction jdbc, l'éditeur de texte Ctrl Z recovery, etc.

Pour des articles plus détaillés sur l'utilisation du modèle mémo dans les modèles de conception Java, veuillez faire attention au site Web PHP chinois !

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal