您的位置:首页 > 编程语言 > Java开发

实例探索Java模式之路——命令模式

2017-08-05 17:20 344 查看
命令模式

1、命令模式属于对象的行为模式。是对命令的封装。
他把一个请求或者操作封装到一个对象中,允许系统使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。
命令模式把发出命令的责任或执行命令的责任分割开,委派给不同对象。

2、每一个命令都是一个操作:请求的一方发出请求要求执行一个操作,接收的一方收到请求,并执行操作。

命令允许请求的一方和接收的一方能够独立演化,具有一下优点:
1、命令模式使用新的命令很容易地被加入到系统里。
2、允许接收请求的一方决定是否要否决请求。
3、能较容易地设计一个命令队列。
4、可以容易地实现对请求的undo和Redo。
5、在需要的情况下,可以较容易地将命令计入日志。

3、命令模式结构:



客户端角色:创建一个具体命令对象并确定其接受者。
抽象命令角色:声明一个给出所有具体命令类的抽象接口。
具体命令角色:定义了一个接受者和行为之间的弱耦合;实现execute()方法,负责调用接受者的相应操作。execute()方法叫执行方法。
请求者角色:负责调用命令对象执行请求,行动方法。
接受者:负责具体实施和执行的一个请求。任何一个类都可以成为接受者,实施和执行请求的方法叫行动方法。

4、一个示意性例子:

首先我们需要知道我们要干什么?请求者要让接受者进行什么操作?

请求者发出动作,接受者执行动作

//客户端,创建具体命令对象并确定其接受者
public class Client {

public static void main(String[] args) {

// 接受者
Reciver reciver = new Reciver();
// 命令对象
Command command = new ConcreteCommand(reciver);
// 请求者
Invoker invoker = new Invoker(command);
invoker.action();//发出动作
}

}

//接受者
public class Reciver {
public Reciver() {
System.out.println("接受者无参构造");
}

// 行动方法
public void action() {
System.out.println("接受者Action has been taken");
}
}

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

//具体命令角色
public class ConcreteCommand implements Command {

private Reciver reciver;

public ConcreteCommand(Reciver reciver) {
this.reciver = reciver;
}

// 执行方法
@Override
public void execute() {
reciver.action();
}

}

//请求者,
public class Invoker {

private Command command;

public Invoker(Command command) {
this.command = command;
}

// 行动方法
public void action() {
command.execute();
}
}

请求者调用命令对象执行请求,命令对象调用接受者的execute()方法进行相应操作,把动作传给接受者,接受者得到命令执行操作。

5、一个录音机的例子:

录音机有播音,倒带,停止的功能,特别符合命令模式。用代码模仿实现这些功能。

//客户端,创建具体命令对象并确定其接受者
//模仿录音机播音,倒带,停止的功能
public class Client {

private static Keypad keypad;// 录音机上的按钮,是命令的请求者

private static AudioPlayer myAudio = new AudioPlayer();// 录音机,是接受者

public static void main(String[] args) {
test1();
}

private static void test1() {
// 命令对象,播音
Command play = new PlayCommand(myAudio);
// 命令对象,停止
Command stop = new StopCommand(myAudio);
// 命令对象,倒带
Command rewind = new RewindCommand(myAudio);

// 请求者
keypad = new Keypad(play, stop, rewind);

// 点击不同按钮,发出不同的命令
keypad.play();
keypad.stop();
keypad.rewind();
keypad.stop();
keypad.play();
keypad.rewind();
}


//接受者,定义接收拥有的所有行为
public class AudioPlayer {
// 行动方法
public void play() {
System.out.println("Playing......");
}

public void stop() {
System.out.println("Rewinding......");
}

public void rewind() {
System.out.println("Stopped!");
}
}

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

//具体命令角色
public class PlayCommand extends Command {

private AudioPlayer myAudio;

public PlayCommand(AudioPlayer myAudio) {
this.myAudio = myAudio;
}

// 执行方法
@Override
public void execute() {
myAudio.play();
}

}

//具体命令角色
public class RewindCommand extends Command {

private AudioPlayer myAudio;

public RewindCommand(AudioPlayer myAudio) {
this.myAudio = myAudio;
}

// 执行方法
@Override
public void execute() {
myAudio.rewind();
}

}
//具体命令角色
public class StopCommand extends Command {

private AudioPlayer myAudio;

public StopCommand(AudioPlayer myAudio) {
this.myAudio = myAudio;
}

// 执行方法
@Override
public void execute() {
myAudio.stop();
}

}

//请求者,
public class Keypad {

private Command playCommand;
private Command rewindCommand;
private Command stopCommand;

public Keypad(Command playCommand, Command rewindCommand,
Command stopCommand) {
this.playCommand = playCommand;
this.rewindCommand = rewindCommand;
this.stopCommand = stopCommand;
}

// 行动方法,播音
public void play() {
playCommand.execute();
}

// 行动方法,停止
public void stop() {
stopCommand.execute();
}

// 行动方法,倒带
public void rewind() {
rewindCommand.execute();
}
}

在上面我们提到命令模式使用新的命令很容易地被加入到系统里的优点,现在我们就在这个录音机加入新的命令。

增加宏命令用于记录操作的所有命令,在任何需要的时候重新把这些记录下来的命令一次性执行。要记录这些命令然后再依次执行必然会用到聚集。

//客户端,创建具体命令对象并确定其接受者
//模仿录音机播音,倒带,停止的功能
public class Client {

private static Keypad keypad;// 录音机上的按钮,是命令的请求者

private static AudioPlayer myAudio = new AudioPlayer();// 录音机,是接受者

public static void main(String[] args) {
test1();
test2();
}

private static void test1() {
// 命令对象,播音
Command play = new PlayCommand(myAudio);
// 命令对象,停止
Command stop = new StopCommand(myAudio);
// 命令对象,倒带
Command rewind = new RewindCommand(myAudio);

// 请求者
keypad = new Keypad(play, stop, rewind);

// 点击不同按钮,发出不同的命令
keypad.play();
keypad.stop();
keypad.rewind();
keypad.stop();
keypad.play();
keypad.rewind();

}

// 增加宏命令记录操作的所有命令
private static void test2() {
// 命令对象,播音
Command play = new PlayCommand(myAudio);
// 命令对象,停止
Command stop = new StopCommand(myAudio);
// 命令对象,倒带
Command rewind = new RewindCommand(myAudio);
// 命令对象,宏
MacroCommand macro = new MacroAudioCommand();

macro.add(play);
macro.add(rewind);
macro.add(stop);
macro.add(play);
macro.add(stop);
macro.add(play);
macro.add(rewind);
macro.add(play);
macro.add(rewind);
macro.add(stop);
macro.execute();
}
}

//抽象宏命令
abstract public class MacroCommand extends Command {

// 宏命令聚集管理方法,可以删除一个成员命令
public abstract void remove(Command toRemove);

// 宏命令聚集管理方法,可以添加一个成员命令
public abstract void add(Command toAdd);

}

import java.util.Vector;

//具体宏命令
public class MacroAudioCommand extends MacroCommand {

private Vector commandList = new Vector();

// 移除指令
@Override
public void remove(Command toRemove) {
commandList.removeElement(toRemove);

}

public void remove(int index) {
commandList.remove(index);

}

// 添加指令
@Override
public void add(Command toAdd) {
commandList.addElement(toAdd);

}

@Override
public void execute() {

Command nextCommand;
System.out.println("Automated playBack of stored commands...");
for (int i = 0; i < commandList.size(); i++) {
nextCommand = (Command) commandList.elementAt(i);
nextCommand.execute();
}

System.out.println("Finshed Automated playBack of stored commands");
}
}

结果输出:
Playing......
Stopped!
Rewinding......
Stopped!
Playing......
Rewinding......
=====================
Automated playBack of stored commands...
Playing......
Stopped!
Rewinding......
Playing......
Rewinding......
Playing......
Stopped!
Playing......
Stopped!
Rewinding......
Finshed Automated playBack of stored commands

7、命令模式使用场景:

1. 命令的发送者和命令执行者有不同的生命周期。命令发送了并不是立即执行。
2. 命令需要进行各种管理逻辑。
3. 需要支持撤消\重做操作(这里不进行详细解读)。

8、命令模式优缺点:
优点:
1、就是将行为请求者和行为实现者解耦(最大优点)。
2、命令的添加特别方便,并且可以方便的制定各种命令和利用现有命令组合出新的命令。
3、如果针对每一类具有共同接口的接受者制作一个调用者,可以控制命令的执行情况。
缺点:
增加系统的复杂性,看看上面的例子就知道了,类的数量有很多。

通过此实例,相信对该模式有了进一步的认识。

每天努力一点,每天都在进步。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息