企业自适应网站制作,邵阳网站开发公司推荐,好123上网主页免费,wordpress会员期限简介
命令模式#xff08;Command Pattern#xff09;是对命令的封装#xff0c;每一个命令都是一个操作#xff1a;请求方发出请求要求执行一个操作#xff1b;接收方收到请求#xff0c;并执行操作。命令模式解耦了请求方和接收方#xff0c;请求方只需请求执行命令Command Pattern是对命令的封装每一个命令都是一个操作请求方发出请求要求执行一个操作接收方收到请求并执行操作。命令模式解耦了请求方和接收方请求方只需请求执行命令不用关心命令怎样被接收、怎样被操作及是否被执行等。命令模式属于行为型设计模式。
通用模板 创建接收者角色该类负责具体实施或执行一个请求。 // 接收者
public class Receiver {public void action() {System.out.println(执行具体操作);}
}创建抽象命令角色定义需要执行的所有命令行为。 // 抽象命令接口
public interface ICommand {void execute();
}创建具体命令角色该类内部维护一个Receiver在其execute方法中调用Receiver的相关方法。 // 具体命令
public class ConcreteCommand implements ICommand {// 直接创建接收者不暴露给客户端private Receiver receiver new Receiver();Overridepublic void execute() {this.receiver.action();}
}创建请求者角色接收客户端的命令并执行命令。 // 请求者
public class Invoker {private ICommand cmd;public Invoker(ICommand cmd) {this.cmd cmd;}public void action(){this.cmd.execute();}
}模板测试
测试代码public class Client {public static void main(String[] args) {ConcreteCommand cmd new ConcreteCommand();Invoker invoker new Invoker(cmd);invoker.action();}
}测试结果执行具体操作应用场景
在日常生活中命令模式是很常见的。比如经历过黑白电视机年代的小伙伴应该都有过这样的经历。那个年代在看电视的时候想要换个频道简直不容易。我们得走到电视机前扭动换台的旋钮一顿“咔咔咔”折腾才能完成频道的切换。如今遥控器的发明简直就是“解放战争”我们躺在沙发上只需要轻轻一按遥控器即可完成频道的切换。这就是命令模式将换台请求和换台处理完全解耦了。 当系统的某项操作具备命令语义且命令实现不稳定变化时可以通过命令模式解耦请求与实现使用抽象命令接口使请求方的代码架构稳定封装接收方具体命令的实现细节。接收方与抽象命令接口呈现弱耦合内部方法无须一致具备良好的扩展性。命令模式主要适用于以下应用场景。 1现实语义中具备“命令”的操作如命令菜单、Shell命令等。 2请求的调用者和接收者需要解耦使得调用者和接收者不直接交互。 3需要抽象出等待执行的行为比如撤销Undo操作和恢复Redo等操作。 4需要支持命令宏即命令组合操作。
优点
1通过引入中间件抽象接口解耦了命令请求与实现。 2扩展性良好可以很容易地增加新命令。 3支持组合命令支持命令队列。 4可以在现有命令的基础上增加额外功能。比如日志记录结合装饰器模式会更加灵活。
缺点
1具体命令类可能过多。 2命令模式的结果其实就是接收方的执行结果但是为了以命令的形式进行架构、解耦请求与实现引入了额外类型结构引入了请求方与抽象命令接口增加了理解上的困难。不过这也是设计模式的通病抽象必然会额外增加类的数量代码抽离肯定比代码聚合更难理解。
“生搬硬套”实战
场景描述
我们可以用一个遥控器控制家用电器如电灯作为例子。在这个场景中遥控器是发出命令的对象而家用电器则是执行命令的对象。
代码开发 创建接收者角色这里指的是实际执行的对象灯 // 定义接收者类即实际执行动作的对象——Light
public class Light {public void turnOn() {System.out.println(Light is on);}public void turnOff() {System.out.println(Light is off);}
}创建抽象命令角色这里指的是抽象命令接口定义执行和取消操作 // 定义一个命令接口
public interface ICommand {void execute();void undo();
}创建具体命令角色这里指的是开灯和关灯的具体命令实现类 // 具体的开灯命令类
public class LightOnCommand implements ICommand{private final Light light;public LightOnCommand(Light light) {this.light light;}Overridepublic void execute() {light.turnOn();}Overridepublic void undo() {light.turnOff();}
}// 具体关灯命令类
public class LightOffCommand implements ICommand {private final Light light;public LightOffCommand(Light light) {this.light light;}Overridepublic void execute() {light.turnOff();}Overridepublic void undo() {light.turnOn();}
}创建请求者角色这里指的就是遥控器 // 定义一个调用者——遥控器类它将保存命令并执行
public class RemoteControl {private ICommand command;public void setCommand(ICommand command) {this.command command;}public void pressButton() {command.execute();}public void undo() {command.undo();}
}至此我们就通过“生搬硬套”命令模式的模板设计出一套遥控器开关灯的案例接下来我们进行测试 测试代码 public class Client {public static void main(String[] args) {Light light new Light();RemoteControl remote new RemoteControl();// 设置打开电灯的命令remote.setCommand(new LightOnCommand(light));remote.pressButton(); // 执行命令打开电灯remote.undo(); // 撤销命令关闭电灯// 设置关闭电灯的命令remote.setCommand(new LightOffCommand(light));remote.pressButton(); // 执行命令关闭电灯remote.undo(); // 撤销命令打开电灯}
}测试结果 Light is on
Light is off
Light is off
Light is on场景描述2
假如我们开发一个播放器播放器有播放功能、拖动进度条功能、停止播放功能、暂停功能我们在操作播放器的时候并不是直接调用播放器的方法而是通过一个控制条去传达指令给播放器内核具体传达什么指令会被封装为一个个按钮。那么每个按钮就相当于对一条命令的封装。用控制条实现了用户发送指令与播放器内核接收指令的解耦。
代码开发2 创建接收者角色这里指的是实际执行的对象播放器 // 定义接收者类即实际执行动作的对象——播放器
public class GPlayer {public void play() {System.out.println(正常播放);}public void speed() {System.out.println(拖动进度条);}public void stop() {System.out.println(停止播放);}public void pause() {System.out.println(暂停播放);}
}创建抽象命令角色这里指的是抽象命令接口定义执行命令操作 // 定义一个命令接口
public interface IAction {void execute();
}创建具体命令角色这里指的是播放、暂停、停止、加速具体命令实现类 // 具体的播放命令
public class PlayAction implements IAction {private GPlayer player;public PlayAction(GPlayer player) {this.player player;}Overridepublic void execute() {player.play();}
}// 具体的暂停命令
public class PauseAction implements IAction {private GPlayer player;public PauseAction(GPlayer player) {this.player player;}Overridepublic void execute() {player.pause();}
}// 具体的停止命令
public class StopAction implements IAction {private GPlayer player;public StopAction(GPlayer player) {this.player player;}Overridepublic void execute() {player.stop();}
}// 具体的拖动进度条命令
public class SpeedAction implements IAction {private GPlayer player;public SpeedAction(GPlayer player) {this.player player;}Overridepublic void execute() {player.speed();}
}创建请求者角色这里指的就是播放器控制面板 import java.util.ArrayList;
import java.util.List;// 定义一个调用者——控制面板类它将保存命令并执行
public class Controller {private ListIAction actions new ArrayList();public void addAction(IAction action) {actions.add(action);}public void execute(IAction action) {action.execute();}public void executes() {for (IAction action : actions) {action.execute();}actions.clear();}
}至此我们就通过“生搬硬套”命令模式的模板设计出一套通过播放器控制面板上的按钮来控制播放器的案例接下来我们进行测试
代码测试public class Client {public static void main(String[] args) {GPlayer player new GPlayer();Controller controller new Controller();controller.execute(new PlayAction(player));controller.addAction(new PauseAction(player));controller.addAction(new PlayAction(player));controller.addAction(new StopAction(player));controller.addAction(new SpeedAction(player));controller.executes();}
}测试结果正常播放
暂停播放
正常播放
停止播放
拖动进度条总结
在软件系统中行为请求者与行为实现者通常是一种紧耦合关系因为这样的实现简单明了。但紧耦合关系缺乏扩展性在某些场合中当需要对行为进行记录、撤销或重做等处理时只能修改源码。而命令模式通过在请求与实现间引入一个抽象命令接口解耦了请求与实现并且中间件是抽象的它由不同的子类实现因此具备扩展性。所以命令模式的本质是解耦命令请求与处理。