设计模式解密(11)- 命令模式

前言:命令模式内容比较多,这里做了拆分

命令模式基础篇 :http://www.cnblogs.com/JsonShare/p/7202133.html

命令模式扩展篇 - 宏命令:http://www.cnblogs.com/JsonShare/p/7206395.html

命令模式扩展篇 - 撤销命令:http://www.cnblogs.com/JsonShare/p/7206513.html

命令模式扩展篇 - 命令队列:http://www.cnblogs.com/JsonShare/p/7206607.html

命令模式扩展篇 - 请求日志:http://www.cnblogs.com/JsonShare/p/7206665.html

4、请求日志

概念:将所有的动作都记录在日志中,并能在系统死机后,重新调用这些动作恢复到之前的状态。当我们执行命令的时候,将历时记录存储在磁盘中。一旦系统死机,我们就可以将命令对象重新加载,并依次调用这些对象的execute()方法。

实现方法:利用对象的序列化把对象保存起来(记录日志),在需要的时候反序列化(恢复事务)。

请求日志文件可以实现很多功能,常用功能如下

  1、什么事情都存在意外,如一旦系统发生故障,日志文件可以为系统提供一种恢复机制,在请求日志文件中可以记录用户对系统的每一步操作,从而让系统能够顺利恢复到某一个特定的状态;

  2 、请求日志也可以用于实现批处理,在一个请求日志文件中可以存储一系列命令对象,例如一个命令队列;

  3、可以将命令队列中的所有命令对象都存储在一个日志文件中,每执行一个命令则从日志文件中删除一个对应的命令对象,防止因为断电或者系统重启等原因造成请求丢失,而且可以避免重新发送全部请求时造成某些命令的重复执行,只需读取请求日志文件,再继续执行文件中剩余的命令即可。

模拟场景(未必真实,领会实质即可):

假如数据库被DBA误操作了,数据全删除了,因为两小时备份了一次数据库,所以现在只能恢复到两小时前的数据;这岂不是很悲剧;要被开除的节奏;还要赔偿公司经济损失;瞬间感觉要死的节奏;

要是在程序里加上请求日志,这个算个鸟,分分钟恢复;

我们把程序执行的所有sql记录下来,这里假设sql都是在这两小时执行的(比较理想,具体情境具体解决);

代码来了:

package com.designpattern.Command.extend.RequestLog;

import java.io.Serializable;

/**
 * 抽象命令类,由于需要将命令对象写入文件,因此它实现了Serializable接口  
 * @author Json
*/
public abstract class Command implements Serializable {
    private static final long serialVersionUID = 1L;
    
    protected String name; //命令名称 
    protected String args; //命令参数  
    protected Operator operator; //接收者对象
      
    public Command(String name) {  
        this.name = name;
    }  
      
    public String getName() {  
        return this.name;  
    }  
      
    public void setName(String name) {  
        this.name = name;  
    }  
      
    public void setOperator(Operator operator) {  
        this.operator = operator;  
    }  
    
    //声明两个抽象的执行方法execute()  
      public abstract void execute(String args);  
      public abstract void execute();
}
package com.designpattern.Command.extend.RequestLog;

import java.io.Serializable;
/**
 * 请求接收者 -- 由于Operator类的对象是Command的成员对象,它也将随Command对象一起写入文件,因此Operator也需要实现Serializable接口  
 * @author Json
*/
public class Operator implements Serializable{
    private static final long serialVersionUID = 1L;

    public void insert(String args) {  
        System.out.println("新增数据:" + args);  
    }  
      
    public void update(String args) {  
        System.out.println("修改数据:" + args);  
    }  
      
    public void delete(String args) {  
        System.out.println("删除数据:" + args);  
    }  
}
package com.designpattern.Command.extend.RequestLog;
/**
 * 具体命令角色类 -- 插入命令
 * @author Json
*/
public class InsertCommand extends Command{
    public InsertCommand(String name) {
        super(name);
    }

    public void execute(String args) {  
        this.args = args;  
        operator.insert(args);  
    }  
      
    public void execute() {  
        operator.insert(this.args);  
    }  
}
package com.designpattern.Command.extend.RequestLog;
/**
 * 具体命令角色类 -- 修改命令
 * @author Json
*/
public class UpdateCommand extends Command{
    public UpdateCommand(String name) {
        super(name);
    }

    public void execute(String args) {  
        this.args = args;  
        operator.update(args);  
    }  
      
    public void execute() {  
        operator.update(this.args);  
    }  
}
package com.designpattern.Command.extend.RequestLog;
/**
 * 具体命令角色类 -- 删除命令
 * @author Json
*/
public class DeleteCommand extends Command{
    public DeleteCommand(String name) {
        super(name);
    }

    public void execute(String args) {  
        this.args = args;  
        operator.delete(args);  
    }  
      
    public void execute() {  
        operator.delete(this.args);  
    }  
}
package com.designpattern.Command.extend.RequestLog;

import java.util.ArrayList;

import com.designpattern.utils.FileUtil;
/**
 * 请求发送者
 * @author Json
*/
public class SqlExecuteTool {
     //定义一个集合来存储每一次操作时的命令对象  
    private ArrayList<Command> commands = new ArrayList<Command>();  
    private Command command;
  
    //注入具体命令对象  
    public void setCommand(Command command) {  
        this.command = command;  
    }  
      
    //执行配置文件修改命令,同时将命令对象添加到命令集合中  
    public void call(String args) {  
        command.execute(args);  
        commands.add(command);  
    }  
      
    //记录请求日志,生成日志文件,将命令集合写入日志文件  
    public void save() {  
        FileUtil.writeCommands(commands);  
    }
      
    //从日志文件中提取命令集合,并循环调用每一个命令对象的execute()方法来实现配置文件的重新设置  
    public void recover() {  
        ArrayList list = FileUtil.readCommands();  
        for (Object obj : list) {  
            ((Command)obj).execute();  
        }  
    }  
}

测试:

package com.designpattern.Command.extend.RequestLog;
/**
 * 测试
 * @author Json
*/
public class Client {
    public static void main(String[] args) {
        SqlExecuteTool tool = new SqlExecuteTool(); //定义请求发送者  
        Operator operator = new Operator(); //定义请求接收者  
          
        Command command;
        
        //执行了很多次SQL
        command = new InsertCommand("增加");  
        command.setOperator(operator);   
        tool.setCommand(command);  
        tool.call("insert xxx");  
          
        command = new InsertCommand("增加");  
        command.setOperator(operator);  
        tool.setCommand(command);  
        tool.call("insert xxx");  
          
        command = new UpdateCommand("修改"); 
        command.setOperator(operator); 
        tool.setCommand(command);  
        tool.call("update xxx");  
          
        command = new DeleteCommand("删除");
        command.setOperator(operator);  
        tool.setCommand(command);          
        tool.call("delete xxx");  
          
        System.out.println("-------------------------------------");
        System.out.println("保存执行的sql");  
        tool.save();
        System.out.println("-------------------------------------");
        System.out.println("恢复执行的sql");  
        System.out.println("-------------------------------------");
        tool.recover(); 
    }
}

结果:

新增数据:insert xxx
新增数据:insert xxx
修改数据:update xxx
删除数据:delete xxx
-------------------------------------
保存执行的sql
-------------------------------------
恢复执行的sql
-------------------------------------
新增数据:insert xxx
新增数据:insert xxx
修改数据:update xxx
删除数据:delete xxx

这里把这两小时的sql又执行了一遍,是不是相当于数据全部恢复了?

我只能脑补情景,具体在实际编程中,还未遇到,我还年轻,不比老司机... O(∩_∩)O哈哈~

     

PS:源码地址   https://github.com/JsonShare/DesignPattern/tree/master 

  

PS:原文地址 http://www.cnblogs.com/JsonShare/p/7206665.html 

 

原文地址:https://www.cnblogs.com/JsonShare/p/7206665.html