zoukankan      html  css  js  c++  java
  • 设计模式解密(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 

     

  • 相关阅读:
    《代码之道》试读:规范书变更请求
    解读ASP.NET MVC 4 规划路线图
    淘宝数据魔方技术架构解析
    《程序员实用算法》试读:1.2.2主要的优化:函数调用
    《软件框架设计的艺术》试读:2.2 模块化应用程序
    磁盘分割原理
    无锡云计算中心3年内到底做了什么
    模式识别的一些资料
    边缘检测算法
    用递归方法来搜索连通区域
  • 原文地址:https://www.cnblogs.com/JsonShare/p/7206665.html
Copyright © 2011-2022 走看看