命令模式定义:
命令模式是一种高内聚的模式,将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。在命令模式中,低层模块对高层模块是不可见的,高层模块对于低层模块的调用都通过命令接收者,降低了两个模块的间的耦合性。命令接收者,将命令请求封装成一个执行方法,命令者只需要下达命令到接收者,就可以达到想要的结果。
通用命令模式框架:
- Receive接收者角色该角色就是干活的角色,命令传递到这里是应该被执行的,具体到我们上面的例子中就是Group的三个实现类。
- Command命令角色需要执行的所有命令都在这里声明。
- Invoker调用者角色接收到命令,并执行命令。
命令模式实现:
需求:装修房子是一个大工程,需要不同的工种配合,有水电工,泥瓦工,还有木工,如果每次都需要亲自找工人会耗费很多精力和时间,这时候包工头的角色出现了,只需要把你的需求命令下达到包工头,那么剩下的事就靠包工头来完成了。
设计思路:抽象工人类Worker实现公共方法,然后根据工种不同实现不同的工人类,命令类Command,接收业主下达的命令,包工头ContractorInvoker,接收业主下发的命令,并依照业务的需求命令对应的工人去执行。
代码实现如下:
/**
*命令模式
* 工人抽象类
*
*/
public abstract class Worker {
//每个工人的工作
protected abstract void work();
//会做也会拆
protected abstract void rollback();
}
/**
* 命令模式
* 泥瓦工
*/
public class BricklayWorker extends Worker{
@Override
protected void work() {
System.out.println("泥瓦匠砌了一道墙");
}
@Override
protected void rollback() {
System.out.println("泥瓦匠拆了一道墙");
}
}
/**
* 命令模式
* 木工
*/
public class CarpentryWorker extends Worker{
@Override
protected void work() {
System.out.println("做一个壁橱");
}
@Override
protected void rollback() {
System.out.println("拆了壁橱");
}
}
/**
* 命名模式
* 电工
*/
public class ElectricianWorker extends Worker {
@Override
protected void work() {
System.out.println("换个灯泡");
}
@Override
protected void rollback() {
System.out.println("换回去");
}
}
/**
* 命令模式
* 接收命令抽象类
*/
public abstract class Command {
protected BricklayWorker bricklayWorker = new BricklayWorker();//泥瓦工
protected CarpentryWorker carpentryWorker = new CarpentryWorker();//木工
protected ElectricianWorker electricianWorker = new ElectricianWorker();//电工
//接收命令
protected abstract void excute();
}
/**
* 命令模式
* 泥瓦工的命令接收类
*/
public class BricklayComand extends Command{
@Override
protected void excute() {
super.bricklayWorker.work();
}
}
/**
* 命令模式
* 木工接收命令类
*/
public class CarpentryComand extends Command{
@Override
protected void excute() {
System.out.println("木匠打了个壁橱");
}
}
/**
* 命令模式
* 拆除
*/
public class RollBackComand extends Command {
@Override
protected void excute() {
super.bricklayWorker.rollback();
}
}
/**
* 命令模式
* 包工头类
*/
public class ContractorInvoker {
//命令类
private Command command;
//接收命令
public void setCommand(Command command) {
this.command = command;
}
//执行命令
public void action(){
command.excute();
}
}
/**
* 业务类
*/
public class Business {
public static void main(String[] args) {
System.out.println("业务主说:给我砌道墙");
ContractorInvoker contractorInvoker = new ContractorInvoker();
//泥瓦工命令
BricklayComand bricklayComand = new BricklayComand();
contractorInvoker.setCommand(bricklayComand);
contractorInvoker.action();
System.out.println("业务主说:给我打个壁橱");
//木工命令
CarpentryComand carpentryComand = new CarpentryComand();
contractorInvoker.setCommand(carpentryComand);
contractorInvoker.action();
System.out.println("业务主说:不喜欢这道墙,给我拆了");
//拆墙命令
RollBackComand rollBackComand = new RollBackComand();
contractorInvoker.setCommand(rollBackComand);
contractorInvoker.action();
}
}
//执行结果
业务主说:给我砌道墙
泥瓦匠砌了一道墙
业务主说:给我打个壁橱
木匠打了个壁橱
业务主说:不喜欢这道墙,给我拆了
泥瓦匠拆了一道墙
从代码中可以看出,业主Business并没有和工人Worker直接交流,他只需要下达命令Command并传递给包工头ContractorInvoker,包工头会去执行业务的命令,命令工人去工作。而根据命令的不同很容易扩展出一个命令类。而工种由于定义了抽象类,也很容易进行扩展。
总结:
命令模式的优点:
- 类间解耦:调用层和接收层没有交互,调用者实际调用的是Command的excute方法,完全不知道真正的执行者,完成了解耦。
- 可扩展性:Command的类的可扩展性强,调用者和Client由于通过父类传递,没有过度耦合。
命令模式的缺点:
- 缺点也是Command的类随着命令的增多而越来越多
参考《设计模式之禅》秦小波著