在平日的开发过程中,稍大一些的项目都会有一些基础功能类,比如文件操作类,数据库操作类等,通常的使用方式即应用场景直接调用这些类的接口立即执行,但是这种操作不是在所有场景中都适用,我们来举几个例子。
有时候需要组织请求执行顺序:小时候玩过跳跳棋,掷骰子并按照骰子的点数组织行走方案,先把所有棋子走到指定位置的棋手获胜。假设我们有一个棋子类,我们可以调用它的行走接口支配其上下左右行走,那么应用场景需要提前组织好此回合自己棋子每一步的行走方向,然后连续执行。这时候应用场景直接调用棋子类的行走接口一步一步立即执行显然不符合需求。
有时候需要对请求进行相同的复杂操作:前阵子做了一个U盾项目,我们基于厂家提供的基础操作接口进行了封装,根据需求封装成了一个可以提供原子操作的类,但是我们发现这个类的每个原子操作接口里都要提前进行相同的初始化(初始化key、创建容器等)。随着原子操作的递增,项目会出现很多重复的代码,并且如果初始化操作发生变化,所有原子操作都需要修改。这个时候就要考虑在原子操作的上层再进行一些封装的必要性了。还有经常遇到对每个请求进行日志记录等操作。
有时候需要行为的请求者和实现者有不同的生命周期:给一个老师做了一个开源项目的扩展,是一个数学模型变形的演示,每一个时间步都需要计算并更新这个数学模型的各种物理属性,各种物理属性的初始化和判断条件都在不同的类中执行(本构模型),具体更新操作在另一个类中执行,这就需要那些初始化类再做完工作后将请求缓存,等所有初始化类工作完后,具体更新类执行缓存中所有存在的请求。
有时候更需要所有请求多线程执行以充分利用处理器:我们见到的常见方法就是线程池,所有行为请求类将请求压入到请求序列中,线程池从请求序列中逐一取出请求并执行。从而实现了行为请求类与行为实现类间的解耦。
总之在很多特殊的应用场景中都需要考虑行为请求类与行为实现类解耦的问题,从而延申出我们今天说的命令模式。
命令模式:将每个请求都封装成单独的对象,从而使我们可以用不同的请求对客户进行参数化,可以对请求排队或记录请求日志,可以支持对请求的撤销。
一、特征
1、请求:这里有三个概念,行为请求者,行为实现者,请求,我们通过封装请求,从而解开行为请求者与行为实现者间的紧耦合,使得在某些场景下行为请求者发出请求后,行为实现者实现行为前,我们搞一些事情成为了可能。
2、我们这里没有太多的关注行为实现者的封装,因为它的封装不是我们着重考虑的东西,我们可以把所有行为的实现封装到一个类里,也可以把每个请求的行为实现都各自封装在各个请求里,后面还有针对行为实现者的职责链模式专门来封装行为实现者的变化。
二、作用:
在某些应用场景里,我们需要使用到的命令请求比较多,并且我们需要灵活的安排操作请求,这使得发出请求命令的对象与实现请求命令的对象间不可以紧耦合。
三、实现:
我们来实现一个跳跳棋的代码:
//Receiver
public class Chess {
public void goLeft()
{
System.out.printf("go Left \n");
}
public void goRight()
{
System.out.printf("go rigth \n");
}
public void goForward()
{
System.out.printf("go forward \n");
}
public void goBack()
{
System.out.printf("go back \n");
}
}
//Commend
public abstract class Direction {
abstract public void GoAlong();
}
//ConcreteCommendA
public class Left extends Direction{
private Chess myChess;
public Left(Chess chess)
{
myChess = chess;
}
@Override
public void GoAlong() {
// TODO Auto-generated method stub
myChess.goLeft();
}
}
//ConcreteCommendB
public class Right extends Direction{
private Chess myChess;
public Right(Chess chess)
{
myChess = chess;
}
@Override
public void GoAlong() {
// TODO Auto-generated method stub
myChess.goRight();
}
}
//ConcreteCommendC
public class Forward extends Direction{
private Chess myChess;
public Forward(Chess chess)
{
myChess = chess;
}
@Override
public void GoAlong() {
// TODO Auto-generated method stub
myChess.goForward();
}
}
//ConcreteCommendD
public class Back extends Direction{
private Chess myChess;
public Back(Chess chess)
{
myChess = chess;
}
@Override
public void GoAlong() {
// TODO Auto-generated method stub
myChess.goBack();
}
}
//Invoker
public class Invoker {
private List<Direction> myList;
public Invoker()
{
myList = new ArrayList<Direction>();
}
public void addCommend(Direction dir)
{
myList.add(dir);
}
public void execCommend()
{
for (int i = 0; i < myList.size(); i++) {
myList.get(i).GoAlong();
if(i>=5)break;
}
}
}
//应用场景
public class Client {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Chess chess = new Chess();
Invoker invoker = new Invoker();
Direction dir = new Forward(chess);
invoker.addCommend(dir);
dir = new Left(chess);
invoker.addCommend(dir);
dir = new Left(chess);
invoker.addCommend(dir);
dir = new Forward(chess);
invoker.addCommend(dir);
dir = new Right(chess);
invoker.addCommend(dir);
dir = new Back(chess);
invoker.addCommend(dir);
dir = new Right(chess);
invoker.addCommend(dir);
invoker.execCommend();
}
}