【设计模式】Command模式

最近想开始多学习一下工作中代码常常使用的设计模式。

除单例模式,工厂模式之外,command模式用的也是比较多的。

在学习了“正统”的设计模式之后,再来看实际项目代码中使用的类似的设计模式,发现还是有差别的——事实上,设计模式更多的是一种思想吧,如果凡事都寻求一个固定的模式,很容易陷入过度设计的误区。

设计模式是前人在开发过程中总结出来的经验,而并非一套标准,实际使用中,需要结合具体的业务来进行设计,而不应该拘泥于固定的模式。

Command模式

基本动机:解耦程序动作的发起与实际执行

简单的例子:
战场上班长(Invoker,调用者)下达命令(Command):机枪掩护(具体的Comnand对象1),步兵冲锋(具体的Command对象2),但实际机枪怎么打,每个步兵(Receiver)怎么冲则属于执行的事,并非都由班长计划好的。不同的兵将会有不同的冲锋路径。Command模式的解耦机制一可实现多态,二可实现异步(动作发起并不意味着马上执行)。

再次梳理一下:
班长(Invoker)下达命令(Command)并指定命令的接收者(Receiver,也是命令的执行者)。之后班长喊“冲”(action),对应的Receiver便开始执行任务。

类图:
这里写图片描述

时序图:
这里写图片描述

代码示例:

命令接收者相关类:

// 接收者01,实现自己的业务逻辑  
class Receiver01 {  
    public void doJob() {  
        System.out.println("接收者01 完成工作 ...\n");  
    }  
}  

// 接收者02,实现自己的业务逻辑  
class Receiver02 {  
    public void doJob() {  
        System.out.println("接收者02 完成工作 ...\n");  
    }  
} 

命令类:

// 抽象命令类,定义了每个具体命令被执行的入口方法execute()  
abstract class AbstractCommand {  
    public abstract void execute();  
}  

// 具体命令类01,通过构造函数的参数决定了该命令由哪个接收者执行  
class Command01 extends AbstsractCommand {  
    private AbstractReceiver receiver = null;  

    public Command01(AbstractReceiver receiver) {  
        this.receiver = receiver;  
    }  

    public void execute() {  
        System.out.println("命令01 被发布 ...");  
        this.receiver.doJob();  
    }  
}  

// 具体命令类02,通过构造函数的参数决定了该命令由哪个接收者执行  
class Command02 extends AbstractCommand {  
    private AbstractReceiver receiver = null;  

    public Command02(AbstractReceiver receiver) {  
        this.receiver = receiver;  
    }  

    public void execute() {  
        System.out.println("命令02 被发布 ...");  
        this.receiver.doJob();  
    }  
} 

调用者类:

// 调用者,负责将具体的命令传送给具体的接收者  
class Invoker {  
    private AbstractCommand command = null;  

    public void setCommand(AbstractCommand command) {  
        this.command = command;  
    }  

    public void action() {  
        this.command.execute();  
    }  
} 

测试类:

//测试类  
public class Client {  
    public static void main(String[] args) {  
        // 创建调用者  
        Invoker invoker = new Invoker();  

        // 创建一个具体命令,并指定接收并执行该命令的具体接收者  
        AbstractCommand command01 = new Command01(new Receiver01());  

        // 给调用者发布一个具体命令
        invoker.setCommand(command01);  

        // 调用者执行命令,其实是将其传送给具体的接收者并让其真正执行  
        invoker.action();

        AbstractCommand command02 = new Command01(new Receiver02());  
        invoker.setCommand(command02);  
        invoker.action();  
    }  
} 

测试结果:
命令01 被发布 …
接收者01 完成工作 …

命令02 被发布 …
接收者02 完成工作 …

特点

Command的模式最大的一个特点就是调用者与接收者的解耦。

实际应用中,Command的Receiver是多种多样的。比如文本编辑器,CopyCommand对应的是Edit控件的Copy接口,ExitCommand可能对应的就是Application的Exit接口,等等。通过Command模式,就可以实现调用的一致性,而Receiver可能还是千差万别的,因此需要在客户端 Client 类中显式指明出来。

项目中的command模式

前面说了,设计模式是从项目中抽象出来的,服务于项目。实际上我工作中遇到的command模式与上面讲的不太一样,大致如下:

一个command基类;

具体的command继承自command基类,对外只暴露execute接口。

业务线程持有多个具体command对象的指针,并在初始化线程的时候通过new操作获得实例化的command对象。

之后业务对外的接口中调用相应command的execute函数来处理具体的业务逻辑。

也就是说,这里并没有receiver这个角色,具体的执行任务由command来承担——这是基于业务本身的特点的。

另外,也没有使用Invoker——业务线程本身就是调用者了,没必要再多此一举进行这一层封装。

总之,先把死的模式学了,再在实际应用中用活起来!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值