设计模式之——Memento模式

Memento模式即快照模式,就是在某一时刻,设定一个状态,在后面随时可以返回到当前状态的模式。

我们拿一个闯关游戏作为举例,一共有十关,每闯一关,玩家所持金额增加一百,而闯关失败就扣一百。初始时,给玩家一百块作为闯关资金,如果十关全部闯玩,并且玩家手中金额不小于0,则胜利,当玩家所持金额小于0,则视为闯关失败,直接退出。

下面看案例代码,有一个玩家类

  • gamer
package site.wangxin520.gof.memento.demo.game;

import java.util.Random;

/**
 * 游戏的类
 * @author wangXgnaw
 *
 */
public class Gamer {

    /**
     * 玩家所持有的金钱
     */
    private int money;
    private Random random = new Random();

    /**
     * 创建玩家,设置初始化money
     * @param money
     */
    public Gamer(int money) {
        this.money = money;
    }

    /**
     * 获取玩家当前所持有的金钱
     * @return
     */
    public int getMoney() {
        return money;
    }

    /**
     * 玩游戏的方法
     */
    public void play(){
        
        //要么闯关成功
        if(random.nextBoolean()){
            System.out.println("闯关成功,加一百块");
            this.money+=100;
        }else{
            System.out.println("闯关失败,扣两百块");
            this.money-=200;
        }
        
    }
    
    
    @Override
    public String toString() {
        return "玩家当前有现金: [money=" + money + "]";
    }
    
}
  • test测试类
package site.wangxin520.gof.memento.demo;

import site.wangxin520.gof.memento.demo.game.Gamer;

/**
 * 快照模式的一个测试类
 * @author wangXgnaw
 *
 */
public class Test {

    public static void main(String[] args) {
        Gamer gamer = new Gamer(100);

        System.out.println("初始时候,玩家状态为:"+gamer);
        
        //玩十局游戏
        for (int i = 0; i < 10; i++) {

            gamer.play();
            
            System.out.println("第"+(i+1)+"局的时候,玩家状态为:"+gamer);
            
            //判断游戏结束
            if(gamer.getMoney()<0){
                System.out.println("玩家失败");
                break;
            }
        }
        System.out.println();

    }

}
  • 此时运行后控制台为:

image

玩家玩到第三局的时候,就失败了。同样多测试几次后也类似,少有的一路顺风直到最后的。可见,这个游戏是有难度的,那么我们怎么去百分百的成功呢。

假设我们设置,在游戏开始前,设置一个快照,保存游戏进度,当游戏开始后,赢了的话,就更新进度,输了的话,就重新开始当前的关卡。

  • 我们设置了一个快照类,用于保存进度的
package site.wangxin520.gof.memento.demo.game;

/**
 * 游戏的快照的类,当需要爆粗的时候,保存一下进度,用于快速恢复!
 * @author wangXgnaw
 *
 */
public class Memento {

    //保存游戏里面的钱
    private int money;

    /**
     * 构造函数,创建一个快照
     * 限定为只能本包中调用
     */
    Memento(int money) {
        this.money=money;
    }
    
    /**
     * 获取快照保存的钱,这里方法的权限为本包中
     * @return
     */
    int getMoney() {
        return money;
    }
}
  • 修改一下玩家类
package site.wangxin520.gof.memento.demo.game;

import java.util.Random;

/**
 * 游戏的类
 * @author wangXgnaw
 *
 */
public class Gamer {

    /**
     * 玩家所持有的金钱
     */
    private int money;
    private Random random = new Random();

    /**
     * 创建玩家,设置初始化money
     * @param money
     */
    public Gamer(int money) {
        this.money = money;
    }

    /**
     * 获取玩家当前所持有的金钱
     * @return
     */
    public int getMoney() {
        return money;
    }

    /**
     * 玩游戏的方法
     */
    public void play(){
        
        //要么闯关成功
        if(random.nextBoolean()){
            System.out.println("闯关成功,加一百块");
            this.money+=100;
        }else{
            System.out.println("闯关失败,扣两百块");
            this.money-=200;
        }
        
    }
    
    /**
     * 创建快照,当前的所持的金额
     * @return Memento 返回一个快照
     */
    public Memento createMemento(){
        return new Memento(this.money);
    }
    
    /**
     * 回退到快照
     * @param memento
     */
    public void restoreMemento(Memento memento){
        this.money=memento.getMoney();
    }
    
    /**
     * 查看快照里面的钱
     * @return
     */
    public int getMementoState(Memento memento){
        return memento.getMoney();
    }

    @Override
    public String toString() {
        return "玩家当前有现金: [money=" + money + "]";
    }
    
}
  • 测试类也修改了一下,当成功,就更新进度,当不成功,就回退
package site.wangxin520.gof.memento.demo;

import site.wangxin520.gof.memento.demo.game.Gamer;
import site.wangxin520.gof.memento.demo.game.Memento;

/**
 * 快照模式的一个测试类
 * @author wangXgnaw
 *
 */
public class Test {

    public static void main(String[] args) {
        Gamer gamer = new Gamer(100);

        System.out.println("初始时候,玩家状态为:"+gamer);
        
        //设置一个快照
        Memento memento=gamer.createMemento();
        
        //玩十局游戏
        for (int i = 0; i < 10; i++) {

            gamer.play();
            
            //当钱减少后,就说明了玩家本局闯关失败,那么就回退回去
            if(gamer.getMoney()<gamer.getMementoState(memento)){
                gamer.restoreMemento(memento);
                //并且,本局重新来过!
                i--;
            }else{
                //本次闯关成功,更新快照
                memento=gamer.createMemento();
            }
            
            System.out.println("第"+(i+1)+"局的时候,玩家状态为:"+gamer);
            
            //判断游戏结束
            if(gamer.getMoney()<0){
                System.out.println("玩家失败");
                break;
            }
        }
        System.out.println();

    }

}
  • 此时控制台输出就变成了:

image

当闯关失败时候,就恢复到快照,成功就继续闯关。这样一来,基本上就是百试不爽的,次次成功了。哈哈哈!!!

原文地址:https://www.cnblogs.com/wangxinblog/p/7734998.html