第17章 命令模式
17.1 命令模式概述
命令模式(Command Pattern):将一个请求封装为一个对象,从而可用不同的对象对客户进行参数化,对请求排队或者记录请求日志,以及支持可撤销的操作。
- 对象行为型模式
- 动作(Action)模式
- 事务(Transaction)模式
17.2 命令模式结构与实现
17.2.1 命令模式结构
- Command(抽象命令类):抽象命令类―般是一个抽象类或接口,在其中声明了用于执行请求的execute()等方法,通过这些方法可以调用请求接收者的相关操作。
- ConcreteCommand(具体命令类):具体命令类是抽象命令类的子类,实现了在抽象命令类中声明的方法,它对应具体的接收者对象,将接收者对象的动作绑定其中。具体命令类在实现execute()方法时将调用接收者对象的相关操作(Action)。
- Invoker(调用者):调用者即请求发送者,它通过命令对象来执行请求。一个调用者并不需要在设计时确定其接收者,因此它只与抽象命令类之间存在关联关系。在程序运行时可以将一个具体命令对象注入其中,再调用具体命令对象的execute()方法,从而实现间接调用请求接收者的相关操作。
- Receiver(接收者):接收者执行与请求相关的操作,具体实现对请求的业务处理。
17.2.2 命令模式实现
Command(抽象命令类):
package designpatterns.command;
public abstract class Command {
public abstract void execute();
}
Invoker(调用者):
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();
}
}
ConcreteCommand(具体命令类):
public class ConcreteCommand extends Command {
private Receiver receiver;//维持一个对请求接收者对象的引用
public void execute() {
receiver.action();//调用请求接收者的业务处理方法action( )
}
}
Receiver(接收者):
public class Receiver {
public void action() {
//具体操作
}
}
17.3 命令模式应用实例
实例说明
为了用户使用方便,某系统提供了一系列功能键,用户可以自定义功能键的功能,例如功能键FunctionButton可以用于退出系统(由SystemExitClass类来实现),也可以用于显示帮助文档(由DisplayHelpClass类来实现)。
用户可以通过修改配置文件改变功能键的用途,现使用命令模式设计该系统,使得功能键类与功能类之间解耦,可为同一个功能键设置不同的功能。
实例类图
- 调用者
- FunctionButton
- 请求接收者
- SystemExitClass
- DisplayHelpClass
- 抽象命令类
- Command
- 具体命令类
- ExitCommand
- HelpCommand
FunctionButton:功能键类,充当请求调用者(请求发送者)。
package designpatterns.command;
public class FunctionButton {
private Command command;//维持一个抽象命令对象的引用
//为功能键注入命令
public void setCommand(Command command) {
this.command = command;
}
//发送请求的方法
public void click() {
System.out.print("单击功能键:");
command.execute();
}
}
Command:抽象命令类。
package designpatterns.command;
public abstract class Command {
public abstract void execute();
}
ExitCommand:退出命令类,充当具体命令类。
package designpatterns.command;
public class ExitCommand extends Command {
private SystemExitClass seObj;//维持对请求接收者的引用
public ExitCommand() {
seObj = new SystemExitClass();
}
//命令执行方法,将调用请求接收者的业务方法
@Override
public void execute() {
seObj.exit();
}
}
HelpCommand:帮助命令类,充当具体命令类。
package designpatterns.command;
public class HelpCommand extends Command {
private DispalyHelpClass hcObj;//维持对请求接收者的引用
public HelpCommand() {
hcObj = new DispalyHelpClass();
}
//命令执行方法,将调用请求接收者的业务方法
@Override
public void execute() {
hcObj.display();
}
}
SystemExitClass:退出系统模拟实现类,充当请求接收者。
package designpatterns.command;
public class SystemExitClass {
public void exit() {
System.out.println("退出系统! ");
}
}
DisplayHelpClass:显示帮助文档模拟实现类,充当请求接收者。
package designpatterns.command;
public class DispalyHelpClass {
public void display(){
System.out.println("显示帮助文档!");
}
}
配置文件config.xml,在配置文件中存储了具体命令类的类名。
<?xml version="1.0"?>
<config>
<className>designpatterns.command.ExitCommand</className>
</config>
XMLUtil:工具类。
package designpatterns.command;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;
public class XMLUtil {
//该方法用于从XML配置文件中提取具体类的类名,并返回一个实例对象
public static Object getBean() {
try {
//创建DOM文档对象
DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dFactory.newDocumentBuilder();
Document doc;
doc = builder.parse(new File("src//designpatterns//command//config.xml"));
//获取包含类名的文本结点
NodeList nl = doc.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;
}
}
}
Client:客户端测试类。
package designpatterns.command;
public class Client {
public static void main(String[] args) {
FunctionButton fb = new FunctionButton();
Command command;
command = (Command) XMLUtil.getBean();
fb.setCommand(command);
fb.click();
}
}