您的位置:首页 > 其它

23种设计模式(18)-命令模式

2017-07-28 11:31 246 查看
命令模式

    一、 概念

    二、 结构

    三、 具体案例 

    四、 宏命令

    五、 命令模式优点  

引子

在程序设计中,经常设计到一个对象需要请求另外一个对象调用其方法达到某种目的,如果请求这不希望或不直接和被请求者打交道,既请求者不包含被请求者的引 用,那么就可以使用命令模式。例如在军队中,指挥官请求三连偷袭敌人,但是指挥官不希望或无法直接与三连取得联系,那么可以将该请求形成一个命令,该命令 的核心是让三连偷袭敌人。只要能让该命令被执行,就会实现偷袭敌人的目的。

命令模式是关于怎样处理一个对象请求到另一个对象调用其方法完成某项任务的一种成熟的模式,这里称提出请求的对象为请求者,被请求的对象为接收者。 在命令模式中,当一个对象请求另一个对象其调用方法时,不和被请求的对象直接打交道,而是把这这种请求封装到一个命令的对象中,起封装的手段是将请求封装 在命令对象的一个方法中。命令模式的核心就是使用命令对象来封装方法调用。既请求者的请求,接受者调用方法。

定义

命令模式属于对象的行为模式。命令模式又称为行动(Action)模式或交易(Transaction)模式。

  命令模式把一个请求或者操作封装到一个对象中。命令模式允许系统使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。

二、结构

命令模式是对命令的封装。命令模式把发出命令的责任和执行命令的责任分割开,委派给不同的对象。

  每一个命令都是一个操作:请求的一方发出请求要求执行一个操作;接收的一方收到请求,并执行操作。命令模式允许请求的一方和接收的一方独立开 来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求是怎么被接收,以及操作是否被执行、何时被执行,以及是怎么被执行的。

命令允许请求的一方和接收请求的一方能够独立演化,从而具有以下的优点:

  (1)命令模式使新的命令很容易地被加入到系统里。

  (2)允许接收请求的一方决定是否要否决请求。

  (3)能较容易地设计一个命令队列。

  (4)可以容易地实现对请求的撤销和恢复。

  (5)在需要的情况下,可以较容易地将命令记入日志。

下面以一个示意性的系统,说明命令模式的结构。



  命令模式涉及到五个角色,它们分别是:

  ●客户端(Client)角色:创建一个具体命令(ConcreteCommand)对象并确定其接收者。

  ●命令(Command)角色:声明了一个给所有具体命令类的抽象接口。

  ●具体命令(ConcreteCommand)角色:定义一个接收者和行为之间的弱耦合;实现execute()方法,负责调用接收者的相应操作。execute()方法通常叫做执行方法。

  ●请求者(Invoker)角色:负责调用命令对象执行请求,相关的方法叫做行动方法。

●接收者(Receiver)角色:负责具体实施和执行一个请求。任何一个类都可以成为接收者,实施和执行请求的方法叫做行动方法。

源代码

//抽象命令者角色
public interface Command {
/**
* 执行方法
*/
void execute();
}

//接收者角色
public class Receiver {
/**
* 真正执行命令相应的操作
*/
public void action() {
System.out.println("执行操作");
}
}

package Command;
//发送者角色
public class Invoker {
/**
* 持有命令对象
*/
private Command command = null;

/**
* 构造方法
*/
public Invoker(Command command) {
this.command = command;
}

/**
* 行动方法
*/
public void action() {

command.execute();
}
}

package Command;

//具体命令者角色
public class ConcreteCommand implements Command {
// 持有相应的接收者对象
private Receiver receiver = null;

/**
* 构造方法
*/
public ConcreteCommand(Receiver receiver) {
this.receiver = receiver;
}

@Override
public void execute() {
// 通常会转调接收者对象的相应方法,让接收者来真正执行功能
receiver.action();
}

}

package Command;
//客户端角色
public class Client {

public static void main(String[] args) {
// 创建接收者
Receiver receiver = new Receiver();
// 创建命令对象,设定它的接收者
Command command = new ConcreteCommand(receiver);
// 创建请求者,把命令对象设置进去
Invoker invoker = new Invoker(command);
// 执行方法
invoker.action();
}

}

三、具体案例

本案例演示在打仗时指挥官(相当于请求者)发出命令给士兵 ,要求士兵完成任务,但是为了安全起见,不是直接叫士兵过来告诉他命令,而是把命令通过电报(相当于命令角色)发给士兵(相当于接收者)

源代码

package Command1;
/**
* 抽象命令者角色
* 封装请求(命令)的若干方法
* 比如指挥官有三条命令
* 1 下蒙汗药  2 策反敌营士兵  3 偷袭敌营指挥官
* 就可以通过抽象命令者角色的execute()方法封装
* 子类有三种具体实现
* @author Administrator
*
*/
public interface Command {
/**
* 执行方法
*/
void execute();
}

package Command1;
/**
* 接收者角色
* 士兵类  负责完成指挥官发出的命令
* @author Administrator
*
*/
public class Soldier {
public void addMedicine(){
System.out.println("下蒙汗药...");
}

public void defectSoldier(){
System.out.println("策反士兵...");
}

public void attackCommander(){
System.out.println("偷袭敌营指挥官...");
}
}

package Command1;

/**
* 请求者角色 指挥官类 由他发出若干命令
*
* @author Administrator
*
*/
public class Commander {
private Command medecineCommand = null;// 持有命令对象
private Command defectCommand = null;// 持有命令对象
private Command attackCommand = null;// 持有命令对象

public void setMedecineCommand(Command medecineCommand) {
this.medecineCommand = medecineCommand;
}

public void setDefectCommand(Command defectCommand) {
this.defectCommand = defectCommand;
}

public void setAttackCommand(Command attackCommand) {
this.attackCommand = attackCommand;
}

// 完成命令下药  通过命令对象来完成
public void finishMedecine() {
// 调用命令对象的执行命令的方法->完成指挥官发出的命令
medecineCommand.execute();
}

// 完成命令策反   通过命令对象来完成
public void finishDefect() {
// 调用命令对象的执行命令的方法->完成指挥官发出的命令
defectCommand.execute();
}
// 完成命令偷袭   通过命令对象来完成
public void finishAttack() {
attackCommand.execute();
}

}

package Command1;
/**
* 具体命令者角色
* 第一条命令 下药
* @author Administrator
*
*/
public class MedicineCommand implements Command {
private Soldier soldier=null;//持有相应的 接收者对象

public MedicineCommand(Soldier soldier) {
this.soldier = soldier;
}

//实现下药的方法
@Override
public void execute() {
soldier.addMedicine();
}

}

package Command1;

/**
* 具体命令者角色
* 第二条命令 策反
* @author Administrator
*
*/
public class DefectCommand implements Command {
private Soldier soldier=null;//持有相应的 接收者对象

public DefectCommand(Soldier soldier) {
this.soldier = soldier;
}

//实现策反的方法
@Override
public void execute() {
soldier.defectSoldier();;
}

}

package Command1;

/**
* 具体命令者角色
* 第三条命令 偷袭
* @author Administrator
*
*/
public class AttackCommand implements Command {
private Soldier soldier=null;//持有相应的 接收者对象

public AttackCommand(Soldier soldier) {
this.soldier = soldier;
}

//实现偷袭的方法
@Override
public void execute() {
soldier.attackCommander();
}

}

package Command1;
/**
* 客户端角色
* 演示
*/

public class Client {
public static void main(String[] args) {
//创建接收者  士兵
Soldier soldier=new Soldier();

//创建命令
Command medecineCommand=new MedicineCommand(soldier);
Command defectCommand=new DefectCommand(soldier);
Command attackCommand=new AttackCommand(soldier);
//创建请求者   指挥官 发出三条命令
Commander commander=new Commander();
//完成下药命令
commander.setMedecineCommand(medecineCommand);
commander.finishMedecine();

//完成策反命令
commander.setDefectCommand(defectCommand);
commander.finishDefect();

//完成偷袭命令
commander.setAttackCommand(attackCommand);
commander.finishAttack();

}

}

结果:

下蒙汗药…

策反士兵…

偷袭敌营指挥官…

四、宏命令

所谓宏命令简单点说就是包含多个命令的命令,是一个命令的组合。指挥官可以把一个一个的命令记录下来,再在任何需要的时候重新把这些记录下来的命令一次性执行,这就是所谓的宏命令集功能 

系统需要一个代表宏命令的接口,以定义出具体宏命令所需要的接口。

public interface MacroCommand extends Command {
/**
* 宏命令聚集的管理方法
* 可以添加一个成员命令
*/
public void add(Command cmd);
/**
* 宏命令聚集的管理方法
* 可以删除一个成员命令
*/
public void remove(Command cmd);
}

具体的宏命令MacroAudioCommand类负责把个别的命令合成宏命令。

package Command1;

import java.util.ArrayList;
import java.util.List;

public class ConcreteMacroCommand implements MacroCommand {
private List<Command> commandList = new ArrayList<Command>();
//添加一条命令
@Override
public void add(Command cmd) {
commandList.add(cmd);
}
//删除一条命令
@Override
public void remove(Command cmd) {
commandList.remove(cmd);
}
//执行
@Override
public void execute() {
for (Command command : commandList) {
command.execute();
}
}

}

package Command1;

public class Client2 {

public static void main(String[] args) {
// 创建接收者 士兵
Soldier soldier = new Soldier();

// 创建命令
Command medecineCommand = new MedicineCommand(soldier);
Command defectCommand = new DefectCommand(soldier);
Command attackCommand = new AttackCommand(soldier);

MacroCommand mc=new ConcreteMacroCommand();
mc.add(medecineCommand);
mc.add(defectCommand);
mc.add(attackCommand);
mc.execute();

mc.remove(attackCommand);
mc.execute();
}

}

结果:

下蒙汗药…

策反士兵…

偷袭敌营指挥官…

=================

下蒙汗药…

策反士兵…

五、命令模式优点

 

●更松散的耦合

  命令模式使得发起命令的对象——客户端,和具体实现命令的对象——接收者对象完全解耦,也就是说发起命令的对象完全不知道具体实现对象是谁,也不知道如何实现。

●更动态的控制

  命令模式把请求封装起来,可以动态地对它进行参数化、队列化和日志化等操作,从而使得系统更灵活。

●很自然的复合命令

  命令模式中的命令对象能够很容易地组合成复合命令,也就是宏命令,从而使系统操作更简单,功能更强大。

●更好的扩展性

  由于发起命令的对象和具体的实现完全解耦,因此扩展新的命令就很容易,只需要实现新的命令对象,然后在装配的时候,把具体的实现对象设置到命令对象中,然后就可以使用这个命令对象,已有的实现完全不用变化。

以上内容来自平时所看书籍和网络资源整理测试所得,如有不完善之处,欢迎指正!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: