15.命令模式

1.什么是命令模式?

将一个请求封装为一个对象,从而可用不同的请求对客户进行参数化,对请求排队或者记录请求日志,以及支持可撤销的操作。

说人话就是:请求发送者和接受者完全解耦,发送者只需要知道如何发送请求,不必指定如何完成请求

举个例子:买点灯炮和开关,都是独立的,通过电线连起来

 

2.命令模式结构

(1)Command(抽象命令类):抽象命令类一般是一个抽象类或接口,在其中声明了用于执行请求的execute()等方法,通过这些方法可以调用请求接受者的相关操作

(2)ConcreteCommand(具体命令类)具体命令类是抽象命令类的子类,实现了在抽象命令类中声明的方法,它对应具体的接受者对象,将接受者对象的动作绑定其中。具体命令类在实现execute()方法时将调用接受者对象的相关操作。

(3)Invoker(调用者)调用者即请求发送者,它通过命令对象来执行请求。一个调用者并不需要在设计师确定其接受者,因此它只与抽象命令类之间存在关联关系。在程序运行时可以将一个具体命令对象注入其中,在调用具体命令对象的execute()方法,从而实现简介调用请求接受者的相关操作。

(4)Receiver(接受者)接受者执行操作

 

3.命令模式实现

(1)抽象命令类代码

/**
 * 抽象命令类代码
 * @author Administrator
 *
 */
public abstract class Command {
	public abstract void execute();
	

}

(2)调用者,它针对抽象命令类进行编程

/**
 * 调用者,它针对抽象命令类进行编程
 * @author Administrator
 *
 */
public class Invoker {
	private Command command;
	
	//构造注入
	public Invoker(Command command){
		this.command = command;
	}
	
	//设值注入
	public void setCommand(Command command){
		this.command = command;
	}
	
	//业务方法,用于调用命令类的execute()方法
	public void call(){
		command.execute();
	}
	
}

(3)请求接收者

/**
 * 请求接收者
 * @author Administrator
 *
 */
public class Receiver {
	public void action(){
		//具体操作
	}

}

(4)具体命令类

/**
 * 具体命令类
 * @author Administrator
 *
 */
public class ConcreteCommand extends Command {
	private Receiver receiver;//维持一个对象请求接受者对象的引用
	
	@Override
	public void execute() {
		receiver.action();//调用请求接受者的业务处理方法action()
		
	}
}

 

4.命令模式实例——功能键与对应功能实现解耦

(1)退出系统模拟实现类,充当请求接受者

/**
 * 退出系统模拟实现类,充当请求接受者
 * @author Administrator
 *
 */
public class SystemExitClass {

	public void exit(){
		System.out.println("退出系统");
	
	}
}

(2)显示帮助文档模拟实现类,充当请求接受者

/**
 * 显示帮助文档模拟实现类,充当请求接受者
 * @author Administrator
 *
 */
public class DisplayHelpClass {
	public void display() {
		System.out.println("显示帮助文档");
	}
}

(3)抽象命令类

/**
 * 抽象命令类
 * @author Administrator
 *
 */
public abstract class Command {
	public abstract void execute();
}

(4)功能键类,充当请求发送者

/**
 * 功能键类,充当请求发送者
 * @author Administrator
 *
 */
public class FunctionButton {
	private controller.commandModuleFunction.Command command;//维持一个抽象命令对象的引用
	
	//设值注入
	public void setCommand(controller.commandModuleFunction.Command command){
		this.command = command;
	}
	
	//发送请求的方法
	public void click(){
		System.out.println("单击功能键");
		command.execute();
	}
}

(5)退出命令类,充当具体命令类

/**
 * 退出命令类,充当具体命令类
 * @author Administrator
 *
 */
public class ExitCommand extends Command {
	private SystemExitClass seObj;//维持对请求接受者的引用
	
	public ExitCommand() {
		seObj = new SystemExitClass();
	}

	//命令执行方法,将调用请求接受者的业务方法
	@Override
	public void execute() {
		seObj.exit();
	}
}

(6)帮助命令类,充当具体命令类

/**
 * 帮助命令类,充当具体命令类
 * @author Administrator
 *
 */
public class HelpCommand extends Command {
	private DisplayHelpClass hcObj;//维持对请求接受者的引用
	
	public HelpCommand() {
		hcObj = new DisplayHelpClass();
	}

	//命令执行方法,将调用请求接受者的业务方法
	@Override
	public void execute() {
		hcObj.display();
	}

}

(7)config.xml

<?xml version="1.0" encoding="UTF-8"?>
<config>
    <className>controller.commandModuleFunction.ExitCommand</className>
</config>

(8)工具类

public class XMLUtil {
    /**
     * 从xml配置文件中提取具体类的类名,并返回一个实例对象
     */
    public static Object getBean(){
        try {
            //创建DOM文档对象
            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = documentBuilderFactory.newDocumentBuilder();
            Document document = builder.parse(new File("src//controller//commandModuleFunction//config.xml"));

            //获取包含类名的文本节点
            NodeList nl = document.getElementsByTagName("className");
            Node classNode = nl.item(0).getFirstChild();
            String cName = classNode.getNodeValue();

            //通过类名生成实例对象并将其返回
            Class c = Class.forName(cName);
            Object obj = c.newInstance();
            return obj;

        }catch (Exception e){
            e.printStackTrace();
            return  null;
        }

    }
}

(9)客户端

public class Client {
	public static void main(String[] args) {
		FunctionButton fb = new FunctionButton();
		Command command;//定义命令对象
		command = (Command)XMLUtil.getBean();//读取配置文件,反射生成对象
		
		fb.setCommand(command);//将命令对象注入功能键
		fb.click();//调用功能键业务方法
	}
}

(10)运行结果

 

5.实现命令队列

当一个请求发送者发送一个请求时有不止一个请求接受者产生响应,这些请求接受者将逐个执行业务方法,完成对请求的处理,此时,通过命令队列来实现。

(1)命令队列

public class CommandQueue {
	//定义一个ArrayList来存储命令队列
	private ArrayList<Command> commands = new ArrayList<Command>();
	
	public void addCommand(Command command) {
		commands.add(command);
		
	}
	
	public void removeCommand(Command command) {
		commands.remove(command);
	}
	
	//循环调用每一个命令对象的execute()方法
	public void execute() {
		for(Object command:commands){
			((Command)command).execute();
		}
	}
}

(2)发送者类

/**
 * 发送者类
 * @author Administrator
 *
 */
public class Invoker {
	private CommandQueue commandQueue;//维持一个CommandQueue对象的引用
		
	//构造注入
	public Invoker(CommandQueue commandQueue) {
		this.commandQueue = commandQueue;
	}
	
	//设置注入
	private void setCommandQueue(CommandQueue commandQueue) {
		this.commandQueue = commandQueue;
	}
	
	//调用CommandQueue类的execu()方法
	public void call() {
		commandQueue.execute();
		
	}
}

 

6.实现撤销操作——计数器进行数学运算,还可以对运算实施撤销操作

(1)加法类充当请求接受者

/**
 * 加法类充当请求接受者
 * @author Administrator
 *
 */
public class Adder {
	private int num = 0;//定义初始值为0
	
	//加法操作,每次将传入的值与num做加法运算,再将结果返回
	public int add(int value) {
		num += value;
		return num;
	}
}

(2)抽象命令类

/**
 * 抽象命令类
 * @author Administrator
 *
 */
public abstract class AbstractCommand {
	public abstract int execute(int value);//声明命令执行方法
	
	public abstract int undo();//声明撤销方法
		

}

(3)具体命令类

/**
 * 具体命令类
 * @author Administrator
 *
 */
public class AddCommand extends AbstractCommand {
	private Adder adder = new Adder();
	private int value;

	@Override
	public int execute(int value) {
		this.value = value;
		return adder.add(value);
	}

	@Override
	public int undo() {
		return adder.add(-value);
	}

}

(4)请求发送者

/**
 * 请求发送者
 * @author Administrator
 *
 */
public class CalculatorForm {
	private AbstractCommand command;
	
	public void setCommand(AbstractCommand command){
		this.command = command;
	}
	
	//调用命令对象的execute()方法执行运算
	public void compute(int value){
		int i = command.execute(value);
		System.out.println("执行运算,结果为:"+i);
	}
	
	//调用命令对象的undo()方法进行撤销
	public void undo() {
		int i = command.undo();
		System.out.println("执行撤销,运算结果为:"+i);
		
	}

}

(5)客户端

public class Client {
	public static void main(String[] args) {
		CalculatorForm form = new CalculatorForm();
		AbstractCommand command;
		command = new AddCommand();
		form.setCommand(command);//想发送者注入请求命令
		
		form.compute(10);
		form.compute(5);
		form.compute(10);
		form.undo();
	}

}

(6)结果

 

7.宏命令

宏命令又叫组合命令,它是组合模式和命令模式联用的产物。宏命令不是一个具体命令类,它拥有一个集合,在该集合中包含了对其他命令对象的引用。

通常宏命令不直接与请求接受者交互,而是通过它的成员来调用请求接受者的方法。当调用宏命令的execut()方法时将递归调用它所包含的每个成员的execute()方法,一个宏命令的成员可以是简单命令,也可以继续是宏命令,执行一个宏命令将触发多个具体宏命令的执行,从而实现批处理

 

8.命令模式优缺点

优:

(1)请求者与接受者不存在直接引用,解耦

(2)新的命令可以很容易加到系统

(3)可以设计命令队列和宏命令

(4)为请求的撤销和恢复提供了一种设计实现方案

 

缺:

回导致过多的具体命令类

 

9.使用环境

(1)调用者和接受者需要解耦

(2)不同时间指定请求,将请求排队和执行请求

(3)命令的撤销和恢复

(4)组合操作

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鹏哥哥啊Aaaa

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值