<其它设计模式介绍及案例源码下载 >
简介:命令模式(Command Pattern)是一种数据驱动的设计模式,它属于行为型模式。请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。
主要解决:在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关系,但某些场合,比如需要对行为进行记录、撤销或重做、事务等处理时,这种无法抵御变化的紧耦合的设计就不太合适。
优点: 1、降低了系统耦合度。 2、新的命令可以很容易添加到系统中去。
缺点:使用命令模式可能会导致某些系统有过多的具体命令类。
使用场景:在某些场合,比如要对行为进行"记录、撤销/重做、事务"等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将"行为请求者"与"行为实现者"解耦?将一组行为抽象为对象,可以实现二者之间的松耦合。
命令模式一般由以下角色组成:
Command(抽象命令类CommandInterf):抽象命令类一般是一个抽象类或接口,在其中声明了用于执行请求的execute()等方法,通过这些方法可以调用请求接收者的相关操作。
ConcreteCommand(具体命令类CommandWrite、CommandCDir):具体命令类是抽象命令类的子类,实现了在抽象命令类中声明的方法,它对应具体的接收者对象,将接收者对象的动作绑定其中。在实现execute()方法时,将调用接收者对象的相关操作(Action)。
Invoker(调用者Invoker):调用者即请求发送者,它通过命令对象来执行请求。一个调用者并不需要在设计时确定其接收者,因此它只与抽象命令类之间存在关联关系。在程序运行时可以将一个具体命令对象注入其中,再调用具体命令对象的execute()方法,从而实现间接调用请求接收者的相关操作。
Receiver(接收者ActionFinisher):接收者请求与执行相关的操作,它具体实现对请求的业务处理。
Client(客户端角色类):最终的客户端调用类。
实现案例(包含撤销、恢复动作的实现):
public interface CommandInterf { //执行命令 public void execute(String commandStr); //撤销命令 public void undo(); //恢复撤销的命令 public void redo(); } public class CommandWrite implements CommandInterf { ActionFinisher af; List<String> undoList=new ArrayList<String> (); List<String> redoList=new ArrayList<String> (); //参数说明:根据需要的不同,不同的Command实现类中,传入的Action类对象不同,本案例以一个Action为例 public CommandWrite() { super(); this.af=new ActionFinisher(); } @Override public void execute(String commandStr) { af.writeTxt(commandStr); undoList.add(commandStr); } @Override public void undo() { if(undoList.size()<=0) { System.out.println("没有可撤销动作"); return; } redoList.add(undoList.get(undoList.size()-1)); //具体实现细节,按需编码 System.out.println("撤销所写内容:"+undoList.get(undoList.size()-1)); undoList.remove(undoList.size()-1); } @Override public void redo() { if(redoList.size()<=0) { System.out.println("没有可恢复动作"); return; } if(undoList.size()<=0) undoList.add(redoList.get(redoList.size()-1)); //具体实现细节,按需编码 System.out.println("恢复撤销内容:"+redoList.get(redoList.size()-1)); redoList.remove(redoList.size()-1); } } public class CommandCDir implements CommandInterf { ActionFinisher af; List<String> undoList=new ArrayList<String> (); List<String> redoList=new ArrayList<String> (); //参数说明:根据需要的不同,不同的Command实现类中,传入的Action类对象不同,本案例以一个Action为例 public CommandCDir() { super(); af=new ActionFinisher(); } @Override public void execute(String dirName) { af.createDir(dirName); undoList.add(dirName); } @Override public void undo() { if(undoList.size()<=0) { System.out.println("没有可撤销动作"); return; } redoList.add(undoList.get(undoList.size()-1)); //具体实现细节,按需编码 System.out.println("撤销动作:"+undoList.get(undoList.size()-1)); undoList.remove(undoList.size()-1); } @Override public void redo() { if(redoList.size()<=0) { System.out.println("没有可恢复动作"); return; } undoList.add(redoList.get(redoList.size()-1)); //具体实现细节,按需编码 System.out.println("恢复撤销动作:"+redoList.get(redoList.size()-1)); redoList.remove(redoList.size()-1); } } public class Invoker { CommandInterf ciA=new CommandWrite(); CommandInterf ciB=new CommandCDir(); public void writeTxt(String commandStr) { ciA.execute(commandStr); } public void writeUndo() { ciA.undo(); } public void writeRedo() { ciA.redo(); } public void createDir(String commandStr) { ciB.execute(commandStr); } public void createUndo() { ciB.undo(); } public void createRedo() { ciB.redo(); } } public class ActionFinisher { /*按理说不同的操作,在不同的动作实现类中完成, 为了代码简便以及案例的易懂将操作放到这一个类中实现*/ public void writeTxt(String commandStr) { System.out.println("向文件中写信息:"+commandStr); } public void createDir(String dirName) { System.out.println("创建一个文件夹,名为:"+dirName); } } public class TestClass { public static void main(String[] args) { Invoker iv=new Invoker(); iv.createDir("MyDir"); iv.createUndo();//第一次撤销 iv.createRedo();//第一次恢复 iv.createUndo();//第二次撤销 iv.createRedo();//第二次恢复 iv.writeTxt("hello world!"); iv.writeUndo(); iv.writeRedo(); iv.writeUndo(); iv.writeRedo(); } }
说明:现在说一下实现多次撤销重做的原理:维护undo和redo两个盛放Command的栈(用List实现),首次执行一个Command时,执行execute()并将其放入undo栈内,同时要清空redo栈;当执行撤销操作时把undo栈内最上面一个Command拿出来执行undo(),然后将其放入redo栈内;执行重做操作时把redo栈内最上面一个Command拿出来执行execute(),然后将其放入undo栈内。有的操作可能只需要记录一个状态或记录修改的文字,有的可能要记录当前所有数据,另外定义一个CommandManager类作为撤销恢复动作的管理实现,其中两个list集合则记录的是Command对象信息。
命令模式的其他扩展案例(宏命令、命令队列、请求日志)不做过多阐述,具体可以参考(https://www.cnblogs.com/JsonShare/p/7206513.html),写的相对详细