设计模式:学习笔记(5)——命令者式
Java设计模式之命令者式
引入命令模式
案列
比如我们要设计一个DOS命令模拟器,它可以接受输入的命令并做出响应。
0.首先我们的DOS模拟器支持三个大类的功能:文件操作类(FileKit)、展示类(DisplayKit)、网络类(NetKit)。
1.建立抽象命令模板(默认所有的命令都可以使用上述三大类):
public abstract class Command { protected DisplayKit displayKit = new DisplayKit(); protected FileKit fileKit =new FileKit(); protected NetKit netKit = new NetKit(); public abstract void execute(); //所有子类都需要实现这个执行方法 }
2.编写具体命令:(这个就是命令的具体操作,可以看出是多个类协同合作的结果)
public class DeleteCommand extends Command { public void execute() { displayKit.flushScreen(); //展示类:首先刷新一下屏幕 fileKit.deleteFile(); //文件类:删除文件 netKit.updateInfo(); //网络类:上传操作日志 displayKit.flushScreen(); //展示类:再次刷新文件 } }
3.编写调用器:(接受命令执行命令)
public class Invoker { private Command command; public void setCommand(Command command) //传入命令 { this.command=command; } public void action() //调用命令的execute()方法 { this.command.execute(); } }
4.客户端调用:
public class Main { public static void main(String[] args) { Invoker MyDOS = new Invoker(); //建立调用器 Command del = new DeleteCommand(); //建立命令 MyDOS.setCommand(del); //传入命令 MyDOS.action(); //执行命令 } }
什么是命令模式
说明:在软件系统中,“行为请求者”与“行为实现者”通常呈现一种“紧耦合”。但在某些场合,比如要对行为进行“记录、撤销/重做、事务”等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将“行为请求者”与“行为实现者”解耦?将一组行为抽象为对象,实现二者之间的松耦合。这就是命令模式(Command Pattern)。[1]
通用类图:
说明:
● Receiver接收者角色
该角色就是干活的角色, 命令传递到这里是应该被执行的。比如这里的文件操作类(FileKit)、展示类(DisplayKit)、网络类(NetKit)● Command命令角色
需要执行的所有命令都在这里声明。比如这里的DeleteCommand。● Invoker调用者角色
要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。这个是客户端真正触发命令并要求命令执行相应操作的地方,也就是说相当于使用命令对象的入口。
模式分析
模式优点
模式缺点
最佳实践
命令模式的Receiver在实际应用中一般都会被封装掉 , 那是因为在项目中: 约定的优先级最高, 每一个命令是对一个或多个Receiver的封装, 我们可以在项目中通过有意义的类名或命令名处理命令角色和接收者角色的耦合关系(这就是约定) , 减少高层模块(Client类) 对低层模块(Receiver角色类) 的依赖关系, 提高系统整体的稳定性。 因此, 建议大家在实际的项目开发时采用封闭Receiver的方法, 减少Client对Reciver的依赖 。
修改后的Command类:
public abstract class Command { //定义一个子类的全局共享变量 protected final Receiver receiver; //实现类必须定义一个接收者 public Command(Receiver _receiver){ this.receiver = _receiver; }
//每个命令类都必须有一个执行命令的方法 public abstract void execute(); }
修改后的命令
public class ConcreteCommand1 extends Command {//声明自己的默认接收者 public ConcreteCommand1(){ super(new ConcreteReciver1()); } //设置新的接收者 public ConcreteCommand1(Receiver _receiver){ super(_receiver); } //每个具体的命令都必须实现一个命令 public void execute() { //业务处理 super.receiver.doSomething(); } }
说明一下:
如果抽象类没有声明默认构造器的话,那么他的子类一定不能存在默认构造器。