命令模式讲解大纲
- 命令模式原理介绍
- 命令模式适用情况分析
- 命令模式具体代码实现
原理介绍:
在软件系统中,“行为请求者”与“行为实现者”通常呈现一种“紧耦合”。但在某些场合,比如要对行为进行“记录、撤销/重做、事务”等处、理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将“行为请求者”与“行为实现者”解耦?将一组行为抽象为对象,实现二者之间的松耦合。这就是命令模式(Command Pattern)。
适用情况分析:
命令模式把命令抽象成对象,根据传入的命令对象来执行命令,从而减少的对象之间的耦合,比如我们有一个遥控器,遥控器有两列按钮,可以控制灯的开和关,音响的开和关,音响声音的增加和减少,那么我们可以使用命令模式来设计,我们设计一个命令接口,包含两个方面,一个是执行命令,一个是返回上一步,通过这个命令接口,我们来定义各种各样的命令对象,比如,开灯命令,关灯命令,开音响命令,关音响命令等,我们可以看出使用命令模式使这个模拟变的很好扩展,控制器和命令的执行耦合度很低,可以很容易的扩展命令和控制器.
具体代码实现:
命令接口:实现此接口即可扩展一个命令对象
package moshi.gunanyi.com.命令模式;
/**
* 命令方法抽象
* 命令模式使命令变成对象来解耦
* @author Administrator
*
*/
public interface Command {
//执行命令
public void execute();
//回退命令
public void undo();
}
灯类:
package moshi.gunanyi.com.命令模式;
public class Light {
private String name;
public Light(String name) {
this.name = name;
}
public void On() {
System.out.println(name+" 被打开");
}
public void Off() {
System.out.println(name+" 被关闭");
}
}
灯的命令:
package moshi.gunanyi.com.命令模式;
//关灯
public class LightOffCommand implements Command {
private Light light;
public LightOffCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
// TODO Auto-generated method stub
light.Off();
}
@Override
public void undo() {
// TODO Auto-generated method stub
light.On();
}
}
package moshi.gunanyi.com.命令模式;
/**
* 灯的开关
* @author Administrator
*
*/
//开灯
public class LightOnCommand implements Command{
private Light light;
public LightOnCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
// TODO Auto-generated method stub
light.On();
}
@Override
public void undo() {
// TODO Auto-generated method stub
light.Off();
}
}
音响类:
package moshi.gunanyi.com.命令模式;
/**
* 音响类
* @author Administrator
*
*/
public class Stereo {
private String name;
private int vol;
private String cdName;
public Stereo(String name) {
this.name = name;
this.vol = 5;
}
public void On() {
System.out.println(name+ " 被打开");
}
public void Off() {
System.out.println(name+" 被关闭");
}
public int getVol() {
return vol;
}
public void setVol(int vol) {
this.vol = vol;
}
public void setCd() {
System.out.println("放入CD");
}
}
音响的命令:
音响的打开:
package moshi.gunanyi.com.命令模式;
/**
* 音响的开关
* @author Administrator
*
*/
public class StereoOnCommand implements Command {
private Stereo stereo;
public StereoOnCommand(Stereo stereo) {
this.stereo = stereo;
}
@Override
public void execute() {
stereo.On();
stereo.setCd();
}
@Override
public void undo() {
stereo.Off();
}
}
音响的关闭:
package moshi.gunanyi.com.命令模式;
/**
* 关闭音响
* @author Administrator
*
*/
public class StereoOffCommand implements Command {
private Stereo stereo;
public StereoOffCommand(Stereo stereo) {
this.stereo = stereo;
}
@Override
public void execute() {
// TODO Auto-generated method stub
stereo.Off();
}
@Override
public void undo() {
// TODO Auto-generated method stub
stereo.On();
}
}
音响声音增加:
package moshi.gunanyi.com.命令模式;
/**
* 音响的声音增加减少
* @author Administrator
*
*/
public class StereoAddVolCommand implements Command {
private Stereo stereo;
public StereoAddVolCommand(Stereo stereo) {
this.stereo = stereo;
}
@Override
public void execute() {
// TODO Auto-generated method stub
int vol = stereo.getVol();
if(vol<11) {
stereo.setVol(++vol);
}
System.out.println("音量增加:"+vol);
}
@Override
public void undo() {
int vol = stereo.getVol();
if(vol>0) {
stereo.setVol(--vol);
}
System.out.println("音量减少:"+vol);
}
}
音响声音减小:
package moshi.gunanyi.com.命令模式;
public class StereoDecVolCommand implements Command {
private Stereo stereo;
public StereoDecVolCommand(Stereo stereo) {
this.stereo = stereo;
}
@Override
public void execute() {
// TODO Auto-generated method stub
int vol = stereo.getVol();
if(vol>0) {
stereo.setVol(--vol);
}
System.out.println("音量减少:"+vol);
}
@Override
public void undo() {
// TODO Auto-generated method stub
int vol = stereo.getVol();
if(vol<11) {
stereo.setVol(++vol);
}
System.out.println("音量增加:"+vol);
}
}
空命令:用于给控制器初始化,不然执行命令的时候需要判断命令是否为空
package moshi.gunanyi.com.命令模式;
public class NoCommand implements Command {
@Override
public void execute() {
// TODO Auto-generated method stub
}
@Override
public void undo() {
// TODO Auto-generated method stub
}
}
控制器接口:
package moshi.gunanyi.com.命令模式;
/**
* 控制器方法抽象
* @author Administrator
*
*/
public interface Control {
//开
public void onButton(int slot);
//关
public void offButton(int slot);
//返回上一次操作
public void undoButton();
}
控制器的实现:
package moshi.gunanyi.com.命令模式;
import java.util.Stack;
public class CommandModeControl implements Control{
private Command[] onCommands;
private Command[] offCommands;
//存储命令用来调用返回上一次操作
private Stack<Command> undoCommand = new Stack<Command>();
public CommandModeControl() {
//共十个按钮
onCommands = new Command[5];
offCommands = new Command[5];
Command noCommand = new NoCommand();
//初始化按钮对象
for(int i=0,len = onCommands.length;i<len;i++) {
onCommands[i] = noCommand;
offCommands[i] = noCommand;
}
}
//设置按钮的命令
public void setCommand(int slot,Command onCommand,Command offCommand) {
onCommands[slot] = onCommand;
offCommands[slot] = offCommand;
}
@Override
public void onButton(int slot) {
onCommands[slot].execute();
undoCommand.push(onCommands[slot]);
}
@Override
public void offButton(int slot) {
offCommands[slot].execute();
undoCommand.push(offCommands[slot]);
}
@Override
public void undoButton() {
undoCommand.pop().undo();
}
}
代码测试:
package moshi.gunanyi.com.命令模式;
/**
* 测试
* @author Administrator
*
*/
public class Test {
public static void main(String[] args) {
//创建两个灯,一个音响
Light keLight = new Light("客厅灯");
Light woLight = new Light("卧室灯");
Stereo stereo = new Stereo("大音响");
Command keLightOnCommand = new LightOnCommand(keLight);
Command keLightOffCommand = new LightOffCommand(keLight);
Command woLightOnCommand = new LightOnCommand(woLight);
Command woLightOffCommand = new LightOffCommand(woLight);
Command stereoOnCommand = new StereoOnCommand(stereo);
Command stereOffCommand = new StereoOffCommand(stereo);
Command stereAddVolCommand = new StereoAddVolCommand(stereo);
Command stereDesVolCommand = new StereoDecVolCommand(stereo);
CommandModeControl commandModeControl = new CommandModeControl();
commandModeControl.setCommand(0, keLightOnCommand, keLightOffCommand);
commandModeControl.setCommand(1, woLightOnCommand, woLightOffCommand);
commandModeControl.setCommand(2, stereoOnCommand, stereOffCommand);
commandModeControl.setCommand(4, stereAddVolCommand, stereDesVolCommand);
commandModeControl.onButton(1);
//commandModeControl.offButton(1);
commandModeControl.undoButton();
commandModeControl.onButton(2);
commandModeControl.onButton(4);
commandModeControl.offButton(4);
commandModeControl.offButton(2);
}
}
测试结果: