设计模式——命令模式
一、定义
1、定义
创建一个命令对象来代表实际行动。命令对象可以把行动(action) 及其参数封装起来,于是这些行动可以被:
- 重复多次
- 取消
- 取消后又再重做
这些都是现代大型应用程序所必须的功能,即“撤销”及“重复”。除此之外,可以用命令模式来实现的功能例子还有:
- 交易行为
- 进度列
- 向导
- 用户界面按钮及功能表项目
- 线程 pool
- 宏收录
2、UML类图
没有命令模式之前,调用者Invoker和被调用者Receiver是直接相连的,强耦合。
命令模式:下面这个类图取自维基百科。多了三个组件Client、Command及Command的实现类ConcreteConmmand
自己画了一个UML类图:
Invoker与Receiver通过Command解耦了,并且由client控制Invoker,Command,Receiver之间的关系
总结:命令模式有两个重要作用:
① 将请求封装成对象,将调用者与被调用者解耦
② 由于将请求封装成了对象,请求可以被重复使用(Command可被不同的对象使用,也可被同一个对象重复调用),另外还支持取消
所以:当需要发出请求的对象与执行请求的对象解耦的时候,使用命令模式。
3、简单实现
public class Light { private String addr; public Light(String addr){ this.addr = addr; } public void on(){ System.out.println(addr + " light on"); } public void off(){ System.out.println(addr + " light off"); } } public interface Command { void execute(); void undo(); } public class LightOnCommand implements Command { private Light light; public LightOnCommand(Light light){ this.light = light; } @Override public void execute() { light.on(); } @Override public void undo() { light.off(); } } public class Invoker { private Command command; public Invoker(Command command){ this.command = command; } public void buttonWasPressed(){ command.execute(); } } public class Client { public static void main(String[] args) { Light light = new Light("room"); LightOnCommand command = new LightOnCommand(light); Invoker invoker = new Invoker(command); invoker.buttonWasPressed(); } }
二、框架中的命令模式
1、JDK中的线程池
前面已经有研究过线程池的源码
现在从命令模式的角度,看待一下线程池的实现。
当没有命令模式设计实现时,一个Thread只能执行一个任务
线程池的设计,通过一个队列解耦Thread与Runnable的耦合关系,ThreadPoolExecutor就相当于client。