命令模式(Command)

一:场景示例

电脑开机过程,大家都用过吧,

1.我们要摁下按钮吧,

2.接着主板“嘀”下检查各个硬件通过

3.启动操作系统

4.进入桌面

二:ok,我们就用这样的场景使用命令模式,且看代码实现,不过实现前还是先介绍下命令模式吧,哈哈

命令模式(Command):将一个请求封装为一个对象,从而使你可以用不同的请求对客户进行参数化,对请求排队或者记录请求日子,以及撤销等操作。(尼玛这个定义太抽象的)

命令模式的 结构和说明:

/**
 * 命令接口,声明执行操作
 * Created by Administrator on 2016/4/22.
 */
public interface Command {
    /**
     * 执行命令对应的操作
     */
    public void execute();
}
package com.dy.command;

/**
 * 命令接受者,真正执行命令的对象
 * Created by Administrator on 2016/4/22.
 */
public class Receiver {

    public  void action(){
        System.out.println("正在执行命令模式...");
    }
}



/**
 * 命令实现
 * 通常持有接受者,并调用接受者的功能来完成命令要执行的操作。
 * Created by Administrator on 2016/4/22.
 */
public class CommandImpl implements Command {
    private Receiver receiver;//持有相应的接受者对象
    private String status;//命令对象可以有自己的状态

    public CommandImpl(Receiver receiver) {
        this.receiver = receiver;
    }

    @Override
    public void execute() {
        //通常调用接受者对象相应方法,由接受者真正执行命令
        this.receiver.action();
    }

}



/**
 * 调用者
 * 要求命令对象执行请求,通常持有命令对象,可以持有很多命令对象
 * 这是客户端真正触发命令并要求命令执行相应操作的地方,相当于所有命令对象的入口
 * Created by Administrator on 2016/4/22.
 */
public class Invoker {

    private Command command;//持有命令对象

    /*
    *设置命令
     */
    public void setCommand(Command command) {
        this.command = command;
    }

    /**
     * 要求命令执行请求
     */
    public void run(){
        command.execute();
    }
}



/**
 * 创建具体命令对象,并设置命令对象的接受者
 * Created by Administrator on 2016/4/22.
 */
public class Client {
    public void doCommand() {
        Receiver receiver = new Receiver();  //创建接受者者
        Command command = new CommandImpl(receiver);//创建命令对象
        Invoker invoker = new Invoker();       //创建Invoker
        invoker.setCommand(command);           //设置命令对象
        invoker.run();
    }

}

class Test{
    public static void main(String[] args) {
        Client client = new Client();
        client.doCommand();
    }
}

执行结果:

正在执行命令模式...

Process finished with exit code 0


三:使用命令模式来实现电脑开机


public interface MainBoard {
    /**
     * 定义接受者功能
     */
    public void open();

    public void reset();
}


/**
 * 命令接受者,真正执行命令的对象
 * Created by Administrator on 2016/4/22.
 */
public class GigaMainBoard implements MainBoard {
    @Override
    public void open() {
        System.out.println("技嘉主板正在开机,请稍后...");
        System.out.println("接通电源...");
        System.out.println("设备检查...");
        System.out.println("启动系统...");
        System.out.println("系统启动完成,进入桌面...");
    }

    @Override
    public void reset() {
        System.out.println("====电脑开始重启===");
        System.out.println("电脑关机中...");
        open();
        System.out.println("====电脑重启完成===");
    }
}




对于用户来说开机就是摁下按钮,别的什么都不想做,也不用关心。所以这里我们要把这个动作抽象下,就相当于用户发出了一个命令或请求,其他用户不care。


/**
 * 命令接口,声明执行操作
 * Created by Administrator on 2016/4/22.
 */
public interface Command {
    /**
     * 执行命令对应的操作
     */
    public void execute();
}



按钮本身并不知道要干什么,更不会知道怎么开机,它只负责把这个命令转给主板,主板才是开机的真正执行者


/**
 * 命令实现
 * 通常持有接受者,并调用接受者的功能来完成命令要执行的操作。
 * Created by Administrator on 2016/4/22.
 */
public class OpenCommand implements Command {
    /**
     * 持有真正的命令实现-接受者
     */
    private MainBoard mainBoard;

    public OpenCommand(MainBoard mainBoard) {
        this.mainBoard = mainBoard;
    }

    @Override
    public void execute() {
        //对于命令对象根本不需要关心命令如何执行(这里指如何开机),转掉接受者方法
        this.mainBoard.open();
    }
}


我后期有补上了重启按钮,所以代码中不要大惊小怪哦,


/**
 * 命令实现
 * 通常持有接受者,并调用接受者的功能来完成命令要执行的操作。
 * Created by Administrator on 2016/4/22.
 */
public class ResetCommand implements Command {
    /**
     * 持有真正的命令实现-接受者
     */
    private MainBoard mainBoard;

    public ResetCommand(MainBoard mainBoard) {
        this.mainBoard = mainBoard;
    }

    @Override
    public void execute() {
        //对于命令对象根本不需要关心命令如何执行,转掉接受者方法
        this.mainBoard.reset();
    }
}



再思考下用户不想和主板直接打交道,压根用户就不需要知道主板是什么就能开机。

其实这里就是解耦的问题了,怎么办?

机箱啊,用机箱封装下不就行了吗,哈哈

接下来我们提供机箱,在机箱上装好按钮(开机按钮)


/**
 * 机箱,本身有按钮,即持有命令对象
 * 调用者
 * 要求命令对象执行请求,通常持有命令对象,可以持有很多命令对象
 * 这是客户端真正触发命令并要求命令执行相应操作的地方,相当于所有命令对象的入口
 * Created by Administrator on 2016/4/22.
 */
public class Box {
    /**
     * 开机命令
     */
    private Command openCommand;
    private Command resetCommand;

    public void setOpenCommand(Command openCommand) {
        this.openCommand = openCommand;
    }

    public void setResetCommand(Command resetCommand) {
        this.resetCommand = resetCommand;
    }

    /**
     * 按下按钮触发方法
     */
    public void openButtonPressed() {
        this.openCommand.execute();
    }

    /**
     * 按下按钮出发方法
     */
    public void resetButtonPressed() {
        this.resetCommand.execute();
    }

}
把主机搬到你面前


/**
         * 把机箱按钮连接线插到主板上
         */
        MainBoard mainBoard = new GigaMainBoard();
        OpenCommand openCommand = new OpenCommand(mainBoard);
        ResetCommand resetCommand = new ResetCommand(mainBoard);

        /**
         * 给机箱安装开机按钮
         */
        Box box = new Box();
        box.setOpenCommand(openCommand);
        box.setResetCommand(resetCommand);
        /**
         * 摁下开机按钮
         */
        box.openButtonPressed();
        /**
         * 重启下试试
         */
        box.resetButtonPressed();

摁下开机和重试按钮试试效果吧,哈哈

技嘉主板正在开机,请稍后...
接通电源...
设备检查...
启动系统...
系统启动完成,进入桌面...
====电脑开始重启===
电脑关机中...
技嘉主板正在开机,请稍后...
接通电源...
设备检查...
启动系统...
系统启动完成,进入桌面...
====电脑重启完成===

Process finished with exit code 0

实际开发过程中Client和Invoker可以融合在一起。

五:命令模式组装过程的调用顺序示意图

命令模式执行过程的调用顺序示意图

转载于:https://my.oschina.net/dyyweb/blog/664521

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值