一:场景示例
电脑开机过程,大家都用过吧,
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可以融合在一起。
五:命令模式组装过程的调用顺序示意图
命令模式执行过程的调用顺序示意图