Java设计模式--命令模式
命令模式
以网上很多人的例子:点餐。
以前吃烧烤,每一个客人都是直接跟烧烤师傅说吃什么,烧烤师傅【又要烧烤又要记住每个客人点了什么】记性差。这里是行为请求者和行为实现者的紧耦合,不好。
现在呢,每个烧烤摊有个服务员,客人想吃啥,直接跟服务员说,服务员把每一份订单给烧烤师傅看,烧烤师傅【只需要根据单子烧烤】效率提升。这里是行为请求者和行为实现者的解耦,好。
大概过程如图:
角色:
客户角色(Client):创造了一个具体命令(ConcreteCommand)并确定其接收者。
命令角色(Command):所有具体命令类的抽象接口。
具体命令角色(ConcreteCommand):定义一个接收者(Receiver)和行为之间的弱耦合;实现execute方法,调用接收者(Receiver)的相关操作。
请求者角色(Invoker):负责调用命令对象(Command)执行请求,相关的方法叫做行动方法。
接收者角色(Receiver):具体实施和执行一个请求。
UML图:
示例:
Command
/** * 命令接口 */ public interface Command { void execute(); }
Receiver
/** * 命令接收者 */ public class Receiver { public Receiver() { } public void action(){ // 命令真正执行的逻辑 System.out.println("~~~~~~~~~~~~~"); } }
ConcreteCommand
/** * 命令接口实现类 */ public class ConcreteCommand implements Command { private Receiver receiver; public ConcreteCommand(Receiver receiver) { this.receiver = receiver; } public void execute() { receiver.action(); } }
Invoker
/** * 命令调用者 */ public class Invoker { private Command command; public Invoker(Command command) { this.command = command; } public void action(){ command.execute(); } }
Client
/** * 命令 + 实现类 * 命令调用者 * 命令接收者 * 客户端 * * 客户端发出命令,由命令调用者负责传递,最终命令接收者执行。客户端不与命令细节直接接触。 */ public class Client { public static void main(String[] args){ Receiver receiver = new Receiver(); Command command = new ConcreteCommand(receiver); Invoker invoker = new Invoker(command); invoker.action(); } }
命令模式有什么好处
实现了命令请求和命令实现的解耦合(中间加了个调用者),说白了,就是让命令实现专注自己职责内的事情,不需要管其他的。
不好的地方就是Command实现类可能会有N个。
实例
来自《Java与模式》中茱莉亚玩收音机的例子。说茱莉亚(客户端)玩收音机,只需要手按相关的按键(命令调用者)即可,不需要关心收音机(命令实现者)播放或者停止的细节。
代码:
Command
public interface Command { void execute(); }
AutoPlayer
/** * 命令实现细节 */ public class AutoPlayer { public void play(){ System.out.println("Play Music"); } public void stop(){ System.out.println("Stop Music"); } }
具体命令:Play
/** * 播放命令 */ public class PlayCommand implements Command { private AutoPlayer autoPlayer; public PlayCommand(AutoPlayer autoPlayer) { this.autoPlayer = autoPlayer; } public void execute() { autoPlayer.play(); } }
具体命令:Stop
/** * 停止命令 */ public class StopCommand implements Command { private AutoPlayer autoPlayer; public StopCommand(AutoPlayer autoPlayer) { this.autoPlayer = autoPlayer; } public void execute() { autoPlayer.stop(); } }
命令调用者:Keyboard
/** * 命令调用者 */ public class KeyBoard { private Command playCommand; private Command stopCommand; public KeyBoard(Command playCommand, Command stopCommand) { this.playCommand = playCommand; this.stopCommand = stopCommand; } public void play(){ playCommand.execute(); } public void stop(){ stopCommand.execute(); } }
客户端:Julia
public class Julia { public static void main(String[] args){ AutoPlayer player = new AutoPlayer(); PlayCommand playCommand = new PlayCommand(player); StopCommand stopCommand = new StopCommand(player); KeyBoard keyBoard = new KeyBoard(playCommand, stopCommand); keyBoard.play(); keyBoard.stop(); } }
回调函数
代码
Callback
/** * 回调接口(命令接口) */ public interface Callback { void callback(); }
商店
/** * 命令调用者(商店店员) */ public class SomeService { private Callback callback; private String phone; public void setCallback(Callback callback) { this.callback = callback; } public void setPhone(String phone) { this.phone = phone; } public void service(){ System.out.println("来货了,给客人【"+ phone +"】打电话......"); callback.callback(); } }
客人
public class Client { public static void main(String[] args){ SomeService service = new SomeService(); service.setPhone("12306"); service.setCallback(() -> { // 这里的角色是具体的命令实现 System.out.println("货到了,我来取!"); }); service.service(); } }
结果:
小LUA
面对敌人的严刑逼供,我一个字也没说,而是一五一十写了下来。