且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

行为型模式之Command模式

更新时间:2022-09-13 20:30:16

命令模式将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,

并且可以对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。

概念描述

把命令的调用者与执行者分开,使双方不必关心对方是如何操作的。
比如有一组文件操作的命令:新建文件、复制文件、删除文件。如果把这三个操作都封装成一个命令类,客户端只需要知道有这三个命令类即可,至于命令类中封装好的逻辑,客户端则无需知道。

在JDK中的体现

允许子类重载部分父类而不需要完全重写。
* java.util.Collections#sort()
* java.io.InputStream#skip()
* java.io.InputStream#read()
* java.util.AbstractList#indexOf()


参与角色

Command类:是一个抽象类,类中对需要执行的命令进行声明,一般来说要对外公布一个execute方法用来执行命令。
ConcreteCommand类:Command类的实现类,对抽象类中声明的方法进行实现。
Client类:最终的客户端调用类。
Invoker类:调用者,负责调用命令。
Receiver类:接收者,负责接收命令并且执行命令。

命令模式实例

当我们调用时,执行的时序首先是调用者类,然后是命令类,最后是接收者类。
一条命令的执行被分成了三步,耦合度要比把所有的操作都封装到一个类中要低的多。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public abstract class Command {
     
    public abstract void execute();
 
}
 
/**
 * 具体命令的实现类
 * @author bingyue56@163.com
 */
public class ConcreteCommand extends Command{
     
    private Receiver receiver;
     
    public ConcreteCommand(Receiver receiver){
        this.receiver=receiver;
    }
 
    /**
     * 具体的调用通过命令接收者来实现
     */
    @Override
    public void execute() {
        this.receiver.action();
    }
}

 

1
2
3
4
5
6
7
8
9
public class Receiver {
 
    /**
     * 真正执行命令操作的代码
     */
    public void action(){
        System.out.println("命令接收者-执行具体业务逻辑");
    }
}

  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
 * 调用者 负责调用命令
 */
public class Invoker {
 
    private Command command; 
     
    public void setCommand(Command command) { 
        this.command = command; 
    
    public void action(){ 
        this.command.execute(); 
    
}

  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
 * 客户端调用
 * @author bingyue56@163.com
 */
public class Client {
 
    public static void main(String[] args){
        //得到业务逻辑执行者
        Receiver receiver=new Receiver();
        //命令类-注入具体业务逻辑接收者
        Command command =new ConcreteCommand(receiver);
        /**
         * 两种调用方式
         * 1.命令类直接调用执行
         */
        command.execute();
        /**
         * 2.通过invoker的方式注入命令
         */
        Invoker invoker=new Invoker();
        invoker.setCommand(command);
        //调用内部command的执行
        invoker.action();
    }
     
}

适用场景

1.使用命令模式作为"CallBack"在面向对象系统中的替代。CallBack讲的便是先将一个函数登记上,然后在以后调用此函数。

2.需要在不同的时间指定请求、将请求排队。一个命令对象和原先的请求发出者可以有不同的生命期。换言之,原先的请求发出者可能已经不在了,而命令对象本身仍然是活动的。这时命令的接收者可以是在本地,也可以在网络的另外一个地址。命令对象可以在序列化之后传送到另外一台机器上去。

3.系统需要支持命令的撤消(undo)。命令对象可以把状态存储起来,等到客户端需要撤销命令所产生的效果时,可以调用undo()方法,把命令所产生的效果撤销掉。命令对象还可以提供redo()方法,以供客户端在需要时,再重新实施命令效果。

4.如果一个系统要将系统中所有的数据更新到日志里,以便在系统崩溃时,可以根据日志里读回所有的数据更新命令,重新调用Execute()方法一条一条执行这些命令,从而恢复系统在崩溃前所做的数据更新。

 



本文转自邴越博客园博客,原文链接:http://www.cnblogs.com/binyue/p/4516498.html,如需转载请自行联系原作者