设计模式笔记之命令模式的使用

<其它设计模式介绍及案例源码下载 >

简介:命令模式(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),写的相对详细

猜你喜欢

转载自blog.csdn.net/fsy9595887/article/details/84402605