`
runfeel
  • 浏览: 902797 次
文章分类
社区版块
存档分类
最新评论

请求发送者与接收者解耦——命令模式(二)

 
阅读更多

3 完整解决方案

为了降低功能键与功能处理类之间的耦合度,让用户可以自定义每一个功能键的功能,Sunny软件公司开发人员使用命令模式来设计“自定义功能键”模块,其核心结构如图4所示:

4 自定义功能键核心结构图

在图4中,FBSettingWindow是“功能键设置”界面类,FunctionButton充当请求调用者,Command充当抽象命令类,MinimizeCommandHelpCommand充当具体命令类,WindowHanlderHelpHandler充当请求接收者。完整代码如下所示:

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

分享到:
评论

相关推荐

    design-pattern-java.pdf

    命令模式-Command Pattern 请求发送者与接收者解耦——命令模式(一) 请求发送者与接收者解耦——命令模式(二) 请求发送者与接收者解耦——命令模式(三) 请求发送者与接收者解耦——命令模式(四) 请求发送者...

    Java设计模式 版本2

    设计模式之代理模式,请求的链式处理——职责链模式,请求发送者与接收者解耦——命令模式,自定义语言的实现——解释器模式,遍历聚合对象中的元素——迭代器模式,协调多个对象之间的交互——中介者模式,撤销功能...

    责任链模式

    这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。 在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给...

    设计模式可复用面向对象软件的基础.zip

    5.12.4 对发送者和接收者解耦 229 5.12.5 总结 231 第6章 结论 232 6.1 设计模式将带来什么 232 6.2 一套通用的设计词汇 232 6.3 书写文档和学习的辅助手段 232 6.4 现有方法的一种补充 233 6.5 重构的目标 233 6.6 ...

    23种设计模式入门到精通详解.txt

    单例模式:某个类只能有一个实例,提供一个全局的...责任链模式:将请求的发送者和接收者解耦,使的多个对象都有处理这个请求的机会。 迭代器模式:一种遍历访问聚合对象中各个元素的方法,不暴露该对象的内部结构。

    php设计模式之职责链模式定义与用法经典示例

    这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。 在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给...

    C#设计模式之行为型模式详解

    责任链模式:为请求创建一个接收者对象的链,对请求的发送者和接收者进行解耦,大部分用于web中吧。。 Task中的continuewith和微软的tpl数据流应该是类似这种模式的实现吧 using System; using System.Collections...

    《设计模式》中文版(23个设计模式的介绍与运用)

    5.12.4 对发送者和接收者解耦 229 5.12.5 总结 231 第6章 结论 232 6.1 设计模式将带来什么 232 6.2 一套通用的设计词汇 232 6.3 书写文档和学习的辅助手段 232 6.4 现有方法的一种补充 233 6.5 重构的目标 233 6.6 ...

    设计模式--C++

    5.12.4 对发送者和接收者解耦 229 5.12.5 总结 231 第 6 章 结论 232 6.1 设计模式将带来什么 2326.2 一套通用的设计词汇 232 6.3 书写文档和学习的辅助手段 232 6.4 现有方法的一种补充 233 6.5 重构的目标 233 6.6...

    GOLF设计模式(C++语言版)

    5.12.4 对发送者和接收者解耦 229 5.12.5 总结 231 第6章 结论 232 6.1 设计模式将带来什么 232 6.2 一套通用的设计词汇 232 6.3 书写文档和学习的辅助手段 232 6.4 现有方法的一种补充 233 6.5 重构的目标 ...

    设计模式(.PDF)

    5.12.4 对发送者和接收者解耦 229 5.12.5 总结 231 第6章 结论 232 6.1 设计模式将带来什么 232 6.2 一套通用的设计词汇 232 6.3 书写文档和学习的辅助手段 232 6.4 现有方法的一种补充 233 6.5 重构的目标 233 6.6 ...

    Erich Gamma、Richard Helm、Ralph Johnson和John Vlissides23种设计模式

    5.12.4 对发送者和接收者解耦 229 5.12.5 总结 231 第6章 结论 232 6.1 设计模式将带来什么 232 6.2 一套通用的设计词汇 232 6.3 书写文档和学习的辅助手段 232 6.4 现有方法的一种补充 233 6.5 重构的目标 233 6.6 ...

    《国外写的,翻译版本》设计模式

    5.12.4 对发送者和接收者解耦 229 5.12.5 总结 231 第6章 结论 232 6.1 设计模式将带来什么 232 6.2 一套通用的设计词汇 232 6.3 书写文档和学习的辅助手段 232 6.4 现有方法的一种补充 233 6.5 重构的目标 233 6.6 ...

    设计模式文档

    5.12.4 对发送者和接收者解耦 229 5.12.5 总结 231 第6章 结论 232 6.1 设计模式将带来什么 232 6.2 一套通用的设计词汇 232 6.3 书写文档和学习的辅助手段 232 6.4 现有方法的一种补充 233 6.5 重构的目标 233 6.6 ...

    RxBus:RxBus for Android,通过RxBus来实现事件的通知和订阅,简化应用组件间的通信,解耦事件的发送者和接收者,避免复杂和容易出错的依赖和生命周期的问题

    RxBus for Android通过RxBus来实现事件的通知和订阅,简化应用组件间的通信,解耦事件的发送者和接收者,避免复杂和容易出错的依赖和生命周期的问题.1.依赖方式Dependency1.1Maven&lt;dependency&gt; &lt;groupId&gt;...

    设计模式 design pattern

    5.12.4 对发送者和接收者解耦 229 5.12.5 总结 231 第6章 结论 232 6.1 设计模式将带来什么 232 6.2 一套通用的设计词汇 232 6.3 书写文档和学习的辅助手段 232 6.4 现有方法的一种补充 233 6.5 重构的目标 233 6.6 ...

    JAVA经典设计模式大全

    5.12.4 对发送者和接收者解耦 229 5.12.5 总结 231 第6章 结论 232 6.1 设计模式将带来什么 232 6.2 一套通用的设计词汇 232 6.3 书写文档和学习的辅助手段 232 6.4 现有方法的一种补充 233 6.5 重构的目标 ...

    设计模式___

    5.12.4 对发送者和接收者解耦 229 5.12.5 总结 231 第6章 结论 232 6.1 设计模式将带来什么 232 6.2 一套通用的设计词汇 232 6.3 书写文档和学习的辅助手段 232 6.4 现有方法的一种补充 233 6.5 重构的目标 233 6.6 ...

    设计模式(Design.Patterns.CHN)

    5.12.4 对发送者和接收者解耦 229 5.12.5 总结 231 第6章 结论 232 6.1 设计模式将带来什么 232 6.2 一套通用的设计词汇 232 6.3 书写文档和学习的辅助手段 232 6.4 现有方法的一种补充 233 6.5 重构的目标 233 6.6 ...

    软件设计师必读的书-设计模式

    5.12.4 对发送者和接收者解耦 229 5.12.5 总结 231 第6章 结论 232 6.1 设计模式将带来什么 232 6.2 一套通用的设计词汇 232 6.3 书写文档和学习的辅助手段 232 6.4 现有方法的一种补充 233 6.5 重构的目标 233 6.6 ...

Global site tag (gtag.js) - Google Analytics