设计模式之备忘录模式

纵饮孤独 提交于 2020-02-20 20:01:14

备忘录模式

  • 备忘录模式和原型模式:

    ​ 备忘录模式是保存对象当时的信息 , 而原型模式是调用clone()方法进行对象的克隆 , 所以我认为可以将备忘录模式进行修改 , 保存对象信息可以直接使用clone()克隆对象 , 然后保存到备忘录中 , 但是这就涉及到浅拷贝和深拷贝的问题 , 如果我们的 “发起人类” (Originator) 内部引用类型稍微复杂的话 , 建议不去使用clone()方法 , 而直接进行信息的保存 .

  • 定义:

    ​ 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态 , 这样以后就可以将该对象恢复到原先保存的状态。备忘录模式就像我们大家玩的游戏存档一样 , 当我们打不过BOSS时 , 就可以先保存游戏进度 , 然后再去进行下一步的行动 . 这样方便我们再次从想要的位置开始。

  • 使用场景:

    1. 需要保存一个对象在某一个时刻的状态或部分状态。
    2. 如果用一个接口来让其他对象得到这些状态,将会暴露对象的实现细节并破坏对象的封装性,一个对象不希望外界直接访问其内部状态,通过中间对象可以间接访问其内部状态。
    3. 浏览器回退、数据库备份和恢复、编辑器撤销和还原、虚拟机生成快照和恢复、Git版本控制、棋牌类游戏悔棋等等。
  • UML:

    1. Main:它是一个普通类,可以创建一个备忘录,并存储它的当前内部状态,也可以使用备忘录来恢复其内部状态,一般将需要保存内部状态的类设计为原发器。
    2. Memento:存储原发器的内部状态,根据原发器来决定保存哪些内部状态。备忘录的设计一般可以参考原发器的设计,根据实际需要确定备忘录类中的属性。需要注意的是,除了原发器本身与负责人类之外,备忘录对象不能直接供其他类使用,原发器的设计在不同的编程语言中实现机制会有所不同。
    3. Gamer:负责人又称为管理者,它负责保存备忘录,但是不能对备忘录的内容进行操作或检查。在负责人类中可以存储一个或多个备忘录对象,它只负责存储对象,而不能修改对象,也无须知道对象的实现细节。

在这里插入图片描述

  • 优点:

    1. 它提供了一种状态恢复的实现机制,使得用户可以方便地回到一个特定的历史步骤,当新的状态无效或者存在问题时,可以使用暂时存储起来的备忘录将状态复原。
    2. 备忘录实现了对信息的封装,一个备忘录对象是一种原发器对象状态的表示,不会被其他代码所改动。备忘录保存了原发器的状态,采用列表、堆栈等集合来存储备忘录对象可以实现多次撤销操作。
  • 缺点:

    1. 资源消耗过大,如果需要保存的原发器类的成员变量太多,就不可避免需要占用大量的存储空间,每保存一次对象的状态都需要消耗一定的系统资源。
  • 样例:

    public class Memento {
        
        private int menoy;
        private ArrayList fruits;
    
        //窄接口,访问部分信息
        public int getMenoy(){
            return menoy;
        }
        
        //宽接口,本包之内皆可访问
        Memento(int menoy){
            this.menoy=menoy;
            fruits=new ArrayList();//每次调用的时候重新生成,很重要
        }
        //宽接口,本包之内皆可访问
        List getFruits(){
            return (List) fruits.clone();
        }
        //宽接口,本包之内皆可访问
        void  addFruits(String fruit){
            fruits.add(fruit);
        }
    
    }
    
    package zyr.dp.memento;
    
    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;
    import java.util.Random;
    
    public class Gamer {
    
        private static  String[] FruitsSame={"香蕉","苹果","橘子","柚子"};
        
        private int menoy;
        private List fruits=new ArrayList();
        private  Random random=new Random();
        
        public int getMenoy(){
            return menoy;
        }
        
        public Gamer(int menoy){
            this.menoy=menoy;
        }
        
        public void bet(){
            int next=random.nextInt(6)+1;
            if(next==1){
                menoy+=100;
                System.out.println("金钱增加了100,当前金钱为:"+menoy);
            }else if(next==2){
                menoy/=2;
                System.out.println("金钱减少了一半,当前金钱为:"+menoy);
            }else if(next==6){
                String f=getFruit();
                fruits.add(f);
                System.out.println("获得了水果:"+f+",当前金钱为:"+menoy);
            }else {
                System.out.println("金钱没有发生改变,当前金钱为:"+menoy);
            }
        }
        
        private String getFruit() {
    
            String prefix="";
            if(random.nextBoolean()){
                prefix="好吃的";
            }
            return prefix+FruitsSame[random.nextInt(FruitsSame.length)];
            
        }
        
        public Memento createMemento(){
            Memento m=new Memento(menoy);
            Iterator it=fruits.iterator();
            while(it.hasNext()){
                String fruit=(String)it.next();
                if(fruit.startsWith("好吃的")){
                    m.addFruits(fruit);
                }
            }
            return m;
        }
        
        public  void restoreMemento(Memento memento){
            this.menoy=memento.getMenoy();
            this.fruits=memento.getFruits();
        }
        
        public String toString(){
            return "Menoy:"+menoy+" ,Fruits:"+fruits;
        }
        
    }
    
    package zyr.dp.test;
    
    import zyr.dp.memento.Gamer;
    import zyr.dp.memento.Memento;
    
    public class Main {
    
        public static void main(String[] args) {
            Gamer gamer=new Gamer(100);
            Memento memento=gamer.createMemento();
            for(int i=0;i<100;i++){
                System.out.println("当前状态:"+i);
                System.out.println("当前金额:"+gamer.getMenoy());
                gamer.bet();
                if(gamer.getMenoy()<memento.getMenoy()/2){
                    System.out.println("金钱过少,恢复到以前的状态:");
                    gamer.restoreMemento(memento);
                    System.out.println("此时状态为:"+gamer);
                }else if(gamer.getMenoy()>memento.getMenoy()){
                    System.out.println("金钱增多,保存当前状态:");
                    memento=gamer.createMemento();
                    System.out.println("此时状态为:"+gamer);
                }
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    
        }
    
    }
    
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!