命令模式的用途:日志请求的具体例子数据库回滚

命令模式 undo,redo参考:http://blog.csdn.net/dengjili/article/details/79533521
序列化与反序列化参考:http://blog.csdn.net/dengjili/article/details/79541333

描述来自于headfirst

某些应用需要将所有的动作都记录在日志中,并能在系统死机后,重新调用这些动作恢复到之前的状态,通过新增store、load两个方法,就能支持这一点。当我们执行命令的时候,调用store方法,将历史记录在磁盘中,一旦系统死机,就可以将命令load重载,并一次调用这些对象的execute方法。许多调用大型数据结构的动作的应用无法在每次改变时快速地存储。通过记录日志,可以将上次检查点之后的所有操作记录下来,如果出现问题,就从检查点开始重新执行操作,检查点是能确保之前的操作全部执行成功的一个时间点。

具体的例子

这里写图片描述

当我们操作数据时候,我们需要向数据库执行A、B、C、D命令,然而,在执行完A、B、C命令后,系统宕机,然后我们找到A、B、C原始命令(序列化),通过执行undo操作,回退到之前正确的状态

具体的例子

对数据库执行,添加,查询,删除,更新操作,在执行删除操作时候,系统报出异常(模拟宕机),然后通过load回滚到之前正常的状态
这里写图片描述

reveiver:数据库操作功能

package headfirst.hd.command.db.reveiver;

import java.io.Serializable;

public class DbOp implements Serializable {

    private static final long serialVersionUID = 1L;

    public void add() {
        System.out.println("对数据【添加】操作");
    }
    public void delete() {
        System.out.println("对数据【删除】操作");
        //模拟宕机
        throw new RuntimeException("当前操作【删除】,系统宕机。。。");

    }
    public void update() {
        System.out.println("对数据【修改】操作");
    }
    public void query() {
        System.out.println("对数据【查询】操作");
    }
    public void addCancel() {
        System.out.println("【回退之前】对数据【添加】操作");
    }
    public void deleteCancel() {
        System.out.println("【回退之前】对数据【删除】操作");
    }
    public void updateCancel() {
        System.out.println("【回退之前】对数据【修改】操作");
    }
    //查询不需要回退操作,空方法,这里只是显示提示
    public void queryCancel() {
        System.out.println("【回退之前】对数据【查询】操作");
    }
}

command接口

package headfirst.hd.command.db.interfaces;

import java.io.Serializable;

public interface Command extends Serializable{
    //执行命令的正常操作
    void execute();
    //回退操作
    void undo();
    //序列化操作,对应execute方法
    void store();
}

concretecommand具体功能

package headfirst.hd.command.db.concretecommand;

import headfirst.hd.command.db.interfaces.Command;
import headfirst.hd.command.db.reveiver.DbOp;
import headfirst.hd.command.db.utils.DBUtils;

public class DbAdd implements Command{

    private static final long serialVersionUID = 1L;
    private DbOp dbOp;

    public DbAdd(DbOp dbOp) {
        super();
        this.dbOp = dbOp;
    }

    @Override
    public void execute() {
        dbOp.add();
        System.out.println("命令执行完成,开始序列化本次命令");
        store();
    }

    @Override
    public void undo() {
        dbOp.addCancel();
    }

    @Override
    public void store() {
        DBUtils.store(this);
    }

}
package headfirst.hd.command.db.concretecommand;

import headfirst.hd.command.db.interfaces.Command;
import headfirst.hd.command.db.reveiver.DbOp;
import headfirst.hd.command.db.utils.DBUtils;

public class DbDelete implements Command{

    private static final long serialVersionUID = 1L;
    private DbOp dbOp;

    public DbDelete(DbOp dbOp) {
        super();
        this.dbOp = dbOp;
    }

    @Override
    public void execute() {
        dbOp.delete();
        System.out.println("命令执行完成,开始序列化本次命令");
        store();
    }

    @Override
    public void undo() {
        dbOp.deleteCancel();
    }

    @Override
    public void store() {
        DBUtils.store(this);
    }

}
package headfirst.hd.command.db.concretecommand;

import headfirst.hd.command.db.interfaces.Command;
import headfirst.hd.command.db.reveiver.DbOp;
import headfirst.hd.command.db.utils.DBUtils;

public class DbQuery implements Command{

    private static final long serialVersionUID = 1L;
    private DbOp dbOp;

    public DbQuery(DbOp dbOp) {
        super();
        this.dbOp = dbOp;
    }

    @Override
    public void execute() {
        dbOp.query();
        System.out.println("命令执行完成,开始序列化本次命令");
        store();
    }

    @Override
    public void undo() {
        dbOp.queryCancel();
    }

    @Override
    public void store() {
        DBUtils.store(this);
    }

}
package headfirst.hd.command.db.concretecommand;

import headfirst.hd.command.db.interfaces.Command;
import headfirst.hd.command.db.reveiver.DbOp;
import headfirst.hd.command.db.utils.DBUtils;

public class DbUpdate implements Command{

    private static final long serialVersionUID = 1L;
    private DbOp dbOp;

    public DbUpdate(DbOp dbOp) {
        super();
        this.dbOp = dbOp;
    }

    @Override
    public void execute() {
        dbOp.update();
        System.out.println("命令执行完成,开始序列化本次命令");
        store();
    }

    @Override
    public void undo() {
        dbOp.updateCancel();
    }

    @Override
    public void store() {
        DBUtils.store(this);
    }

}

invoker控制器:DbControl

package headfirst.hd.command.db.invoker;

import java.util.ArrayList;
import java.util.List;

import headfirst.hd.command.db.interfaces.Command;
import headfirst.hd.command.db.utils.DBUtils;

public class DbControl {
    private List<Command> commands = new ArrayList<Command>();

    public void setCommand(Command command) {
        commands.add(command);
    }

    public void startExecutes() {
        for (Command command : commands) {
            command.execute();
        }
    }

    //额外方法,这个方法应该不放在这个类中,这里简化操作,放在这里
    public void loadComands() {
        for (Command command : DBUtils.load()) {
            command.undo();
        }
    }
}

工具类

package headfirst.hd.command.db.utils;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

//单件模式
public class SerializableHelper {

    public static String FILE_NAME = "a.txt";

    private static class SingletonHolder {
        private static SerializableHelper instance = new SerializableHelper();

        private static ObjectOutputStream oos;

        static {
            try {
                FileOutputStream fos = new FileOutputStream(FILE_NAME);
                oos = new ObjectOutputStream(fos);
            } catch (IOException e) {
                //这里简单处理
                e.printStackTrace();
            }
        }

    }

    private SerializableHelper() {
    }

    public static SerializableHelper getInstance() {
        return SingletonHolder.instance;
    }

    public static ObjectOutputStream getOOS() {
        return SingletonHolder.oos;
    }

    //暂不处理
    public static void release() {

    }

    //必须获取最新的,不然一开始加载的就是空文件
/*  public static ObjectInputStream getOIS() {
        return SingletonHolder.ois;
    }*/
}
package headfirst.hd.command.db.utils;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;

import headfirst.hd.command.db.interfaces.Command;

public class DBUtils {

    public static void store(Command command) {
        ObjectOutputStream oos = SerializableHelper.getOOS();
        try {
            oos.writeObject(command);
        } catch (IOException e) {
            // 这里不能抛异常,子类异常不能超过父类异常,简单处理
            e.printStackTrace();
        }
    }

    public static List<Command> load() {
        List<Command> commands = new ArrayList<Command>();
        FileInputStream fis = null;

        try {
            fis = new FileInputStream(SerializableHelper.FILE_NAME);
            ObjectInputStream ois = new ObjectInputStream(fis);
            while (true) {
                Object object = ois.readObject();
                //if (object instanceof Command),未考察区别,大多数人用的下面方法
                if (Command.class.isAssignableFrom(object.getClass())) {
                    Command command = (Command) object;
                    commands.add(command);
                }
            }
        } catch (Exception e) {
            //请百度:ObjectInputStream判断文件是否序列化完毕的思路,由于是模拟系统宕机,不可能是文件末标志结束符,这里用异常方式
            //读取到文件末,会抛异常,这里返回null,作为判断文件结束条件
        } finally {
            try {
                if (fis != null) {
                    fis.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return commands;
    }
}

模拟数据库操作,报错

package headfirst.hd.command.db;

import headfirst.hd.command.db.concretecommand.DbAdd;
import headfirst.hd.command.db.concretecommand.DbDelete;
import headfirst.hd.command.db.concretecommand.DbQuery;
import headfirst.hd.command.db.concretecommand.DbUpdate;
import headfirst.hd.command.db.invoker.DbControl;
import headfirst.hd.command.db.reveiver.DbOp;

public class DriveTest {

    public static void main(String[] args) {
        //invoker
        DbControl dbControl = new DbControl();
        //reveiver
        DbOp dbOp = new DbOp();
        //concretecommand
        DbAdd dbAdd = new DbAdd(dbOp);
        DbQuery dbQuery = new DbQuery(dbOp);
        DbDelete dbDelete = new DbDelete(dbOp);
        DbUpdate dbUpdate = new DbUpdate(dbOp);
        //绑定
        dbControl.setCommand(dbAdd);
        dbControl.setCommand(dbQuery);
        dbControl.setCommand(dbDelete);  //报错
        dbControl.setCommand(dbUpdate);

        dbControl.startExecutes();
    }

}

测试结果
这里写图片描述

模拟恢复

package headfirst.hd.command.db;

import headfirst.hd.command.db.invoker.DbControl;

public class LoadTest {

    public static void main(String[] args) {
        //invoker
        DbControl dbControl = new DbControl();
        //加载异常时候的命令,回退
        dbControl.loadComands();
    }

}

测试结果
这里写图片描述

预期结果

满足

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值