3 完整解决方案
为了降低功能键与功能处理类之间的耦合度,让用户可以自定义每一个功能键的功能,Sunny软件公司开发人员使用命令模式来设计“自定义功能键”模块,其核心结构如图4所示:
图4 自定义功能键核心结构图
在图4中,FBSettingWindow是“功能键设置”界面类,FunctionButton充当请求调用者,Command充当抽象命令类,MinimizeCommand和HelpCommand充当具体命令类,WindowHanlder和HelpHandler充当请求接收者。完整代码如下所示:
import java.util.*;
//功能键设置窗口类
class FBSettingWindow {
private String title; //窗口标题
//定义一个ArrayList来存储所有功能键
private ArrayList<FunctionButton> functionButtons = new ArrayList<FunctionButton>();
public FBSettingWindow(String title) {
this.title = title;
}
public void setTitle(String title) {
this.title = title;
}
public String getTitle() {
return this.title;
}
public void addFunctionButton(FunctionButton fb) {
functionButtons.add(fb);
}
public void removeFunctionButton(FunctionButton fb) {
functionButtons.remove(fb);
}
//显示窗口及功能键
public void display() {
System.out.println("显示窗口:" + this.title);
System.out.println("显示功能键:");
for (Object obj : functionButtons) {
System.out.println(((FunctionButton)obj).getName());
}
System.out.println("------------------------------");
}
}
//功能键类:请求发送者
class FunctionButton {
private String name; //功能键名称
private Command command; //维持一个抽象命令对象的引用
public FunctionButton(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
//为功能键注入命令
public void setCommand(Command command) {
this.command = command;
}
//发送请求的方法
public void onClick() {
System.out.print("点击功能键:");
command.execute();
}
}
//抽象命令类
abstract class Command {
public abstract void execute();
}
//帮助命令类:具体命令类
class HelpCommand extends Command {
private HelpHandler hhObj; //维持对请求接收者的引用
public HelpCommand() {
hhObj = new HelpHandler();
}
//命令执行方法,将调用请求接收者的业务方法
public void execute() {
hhObj.display();
}
}
//最小化命令类:具体命令类
class MinimizeCommand extends Command {
private WindowHanlder whObj; //维持对请求接收者的引用
public MinimizeCommand() {
whObj = new WindowHanlder();
}
//命令执行方法,将调用请求接收者的业务方法
public void execute() {
whObj.minimize();
}
}
//窗口处理类:请求接收者
class WindowHanlder {
public void minimize() {
System.out.println("将窗口最小化至托盘!");
}
}
//帮助文档处理类:请求接收者
class HelpHandler {
public void display() {
System.out.println("显示帮助文档!");
}
}
为了提高系统的灵活性和可扩展性,我们将具体命令类的类名存储在配置文件中,并通过工具类XMLUtil来读取配置文件并反射生成对象,XMLUtil类的代码如下所示:
import javax.xml.parsers.*;
import org.w3c.dom.*;
import org.xml.sax.SAXException;
import java.io.*;
public class XMLUtil {
//该方法用于从XML配置文件中提取具体类类名,并返回一个实例对象,可以通过参数的不同返回不同类名节点所对应的实例
public static Object getBean(int i) {
try {
//创建文档对象
DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dFactory.newDocumentBuilder();
Document doc;
doc = builder.parse(new File("config.xml"));
//获取包含类名的文本节点
NodeList nl = doc.getElementsByTagName("className");
Node classNode = null;
if (0 == i) {
classNode = nl.item(0).getFirstChild();
}
else {
classNode = nl.item(1).getFirstChild();
}
String cName = classNode.getNodeValue();
//通过类名生成实例对象并将其返回
Class c = Class.forName(cName);
Object obj = c.newInstance();
return obj;
}
catch(Exception e){
e.printStackTrace();
return null;
}
}
}
配置文件config.xml中存储了具体建造者类的类名,代码如下所示:
<?xml version="1.0"?>
<config>
<className>HelpCommand</className>
<className>MinimizeCommand</className>
</config>
编写如下客户端测试代码:
class Client {
public static void main(String args[]) {
FBSettingWindow fbsw = new FBSettingWindow("功能键设置");
FunctionButton fb1,fb2;
fb1 = new FunctionButton("功能键1");
fb2 = new FunctionButton("功能键1");
Command command1,command2;
//通过读取配置文件和反射生成具体命令对象
command1 = (Command)XMLUtil.getBean(0);
command2 = (Command)XMLUtil.getBean(1);
//将命令对象注入功能键
fb1.setCommand(command1);
fb2.setCommand(command2);
fbsw.addFunctionButton(fb1);
fbsw.addFunctionButton(fb2);
fbsw.display();
//调用功能键的业务方法
fb1.onClick();
fb2.onClick();
}
}
编译并运行程序,输出结果如下:
显示窗口:功能键设置
显示功能键:
功能键1
功能键1
------------------------------
点击功能键:显示帮助文档!
点击功能键:将窗口最小化至托盘!
|
如果需要修改功能键的功能,例如某个功能键可以实现“自动截屏”,只需要对应增加一个新的具体命令类,在该命令类与屏幕处理者(ScreenHandler)之间创建一个关联关系,然后将该具体命令类的对象通过配置文件注入到某个功能键即可,原有代码无须修改,符合“开闭原则”。在此过程中,每一个具体命令类对应一个请求的处理者(接收者),通过向请求发送者注入不同的具体命令对象可以使得相同的发送者对应不同的接收者,从而实现“将一个请求封装为一个对象,用不同的请求对客户进行参数化”,客户端只需要将具体命令对象作为参数注入请求发送者,无须直接操作请求的接收者。
【作者:刘伟 http://blog.csdn.net/lovelion】
分享到:
相关推荐
命令模式-Command Pattern 请求发送者与接收者解耦——命令模式(一) 请求发送者与接收者解耦——命令模式(二) 请求发送者与接收者解耦——命令模式(三) 请求发送者与接收者解耦——命令模式(四) 请求发送者...
命令模式通过将请求封装为对象,使得请求的发送者和接收者之间解耦。它提供了灵活的操作管理方式,支持可撤销操作、日志记录和宏命令等功能。在这个示例中,命令模式展示了如何通过遥控器对象控制灯的开启和关闭,...
总的来说,命令模式提供了一种方式,使得请求的发送者和接收者之间解耦,同时增强了系统的灵活性和可扩展性。通过这种方式,我们可以更加方便地管理和组织复杂的系统。在实际开发中,特别是在需要实现撤销操作或事务...
命令模式是一种设计模式,属于对象行为型模式,其主要目的是将请求发送者和接收者解耦,使得两者之间没有直接的引用关系。这种模式通过引入命令对象,将一个请求封装成一个独立的对象,使得发送者只需关注如何发送...
总结来说,命令模式通过引入命令对象,将请求的发送者与接收者解耦,增强了系统的灵活性和可扩展性。在Struts这样的Web框架中,这种模式使得我们可以更方便地管理和调度请求,同时也便于测试和维护。UML文档对于理解...
命令模式的核心思想是将请求的发送者与接收者解耦。发送者不直接调用接收者的具体方法,而是通过命令对象来调用。这样,发送者和接收者之间就没有直接的依赖关系,可以独立变化。命令模式的关键在于定义一个命令接口...
总结一下,命令模式提供了一种方式来将请求封装为独立的对象,使得请求的发送者和接收者解耦。通过定义命令接口和具体命令类,我们可以轻松地添加新的命令,同时保持系统的灵活性和可扩展性。在Java中,命令模式是...
- 解耦调用者和接收者:命令模式将请求封装为对象,因此调用者不需要直接了解接收者的细节,降低了系统中各部分的耦合度。 - 支持撤销和重做操作:由于命令对象的历史状态可以被保存下来,因此可以实现命令的撤销和...
- **松耦合**:调用者与接收者之间的依赖关系被移除,调用者不再需要直接了解接收者的具体实现,只需要知道如何发送请求即可。 - **可扩展性**:添加新的命令只需创建新的具体命令类,不需修改原有系统。 - **可撤销...
命令模式是一种行为设计模式,它将请求封装为一个对象,从而使你可用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。在软件工程中,这种模式广泛应用在各种场景中,以提高代码的灵活...
命令模式是一种行为设计模式,它将请求封装为一个对象,从而使你可用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。在iOS开发中,命令模式尤其适用于处理事件驱动的编程场景,因为...
在C#编程中,命令模式常用于实现解耦发送者和接收者,提高代码的灵活性和可扩展性。 在"命令模式.zip"这个压缩包中,我们可能会找到以下几个关键部分: 1. **命令接口(Command Interface)**:这是所有具体命令类...
1. **松耦合**:命令模式将请求者与接收者解耦,两者无需直接交互,降低了系统的复杂性。 2. **可扩展性**:添加新命令只需要实现新的具体命令类,无需修改已有代码。 3. **可撤销操作**:可以通过实现undo()方法来...
首先,命令模式的核心思想是"将命令的发送者与接收者解耦"。它包含四个角色:命令接口(Command)、具体命令(Concrete Command)、请求者(Invoker)和接收者(Receiver)。命令接口定义了执行操作的方法,具体命令...
命令模式的核心是将请求者(Invoker)与执行者(Receiver)解耦,通过引入命令(Command)接口和具体命令(Concrete Command)类来实现。在该模式中,有四个主要角色: 1. **命令(Command)接口**:定义了一个接收...
总的来说,命令模式是设计模式中的重要一环,它通过封装请求行为,使得请求发送者和接收者解耦,提高了系统的灵活性和可维护性。在C++中,利用面向对象特性,我们可以方便地实现和应用这一模式。
1. **解耦**:命令模式将请求发送者与接收者解耦,两者无需直接交互,降低了系统的耦合度。 2. **可扩展性**:容易添加新的命令而不影响现有代码,符合开闭原则。 3. **支持撤销操作**:通过实现命令的`undo()`方法...
命令模式的核心思想是解耦调用者(Client)与接收者(Receiver),通过引入命令(Command)接口作为两者之间的桥梁。调用者不再直接调用接收者的具体方法,而是创建一个实现了命令接口的对象,并将该对象传递给接收...