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

3 完整解决方案

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

 

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

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

  1. import java.util.*;  
  2.   
  3. //功能键设置窗口类  
  4. class FBSettingWindow {  
  5.     private String title; //窗口标题  
  6.     //定义一个ArrayList来存储所有功能键  
  7.     private ArrayList functionButtons = new ArrayList();  
  8.       
  9.     public FBSettingWindow(String title) {  
  10.         this.title = title;  
  11.     }  
  12.       
  13.     public void setTitle(String title) {  
  14.         this.title = title;  
  15.     }  
  16.       
  17.     public String getTitle() {  
  18.         return this.title;  
  19.     }  
  20.       
  21.     public void addFunctionButton(FunctionButton fb) {  
  22.         functionButtons.add(fb);  
  23.     }  
  24.       
  25.     public void removeFunctionButton(FunctionButton fb) {  
  26.         functionButtons.remove(fb);  
  27.     }  
  28.       
  29.     //显示窗口及功能键  
  30.     public void display() {  
  31.         System.out.println("显示窗口:" + this.title);  
  32.         System.out.println("显示功能键:");  
  33.         for (Object obj : functionButtons) {  
  34.             System.out.println(((FunctionButton)obj).getName());  
  35.         }  
  36.         System.out.println("------------------------------");  
  37.     }     
  38. }  
  39.   
  40. //功能键类:请求发送者  
  41. class FunctionButton {  
  42.     private String name; //功能键名称  
  43.     private Command command; //维持一个抽象命令对象的引用  
  44.       
  45.     public FunctionButton(String name) {  
  46.         this.name = name;  
  47.     }  
  48.       
  49.     public String getName() {  
  50.         return this.name;  
  51.     }  
  52.       
  53.     //为功能键注入命令  
  54.     public void setCommand(Command command) {  
  55.         this.command = command;  
  56.     }  
  57.       
  58.     //发送请求的方法  
  59.     public void onClick() {  
  60.         System.out.print("点击功能键:");  
  61.         command.execute();  
  62.     }  
  63. }  
  64.   
  65. //抽象命令类  
  66. abstract class Command {  
  67.     public abstract void execute();  
  68. }  
  69.   
  70. //帮助命令类:具体命令类  
  71. class HelpCommand extends Command {  
  72.     private HelpHandler hhObj; //维持对请求接收者的引用  
  73.       
  74.     public HelpCommand() {  
  75.         hhObj = new HelpHandler();  
  76.     }  
  77.       
  78.     //命令执行方法,将调用请求接收者的业务方法  
  79.     public void execute() {  
  80.         hhObj.display();  
  81.     }  
  82. }  
  83.   
  84. //最小化命令类:具体命令类  
  85. class MinimizeCommand extends Command {  
  86.     private WindowHanlder whObj; //维持对请求接收者的引用  
  87.       
  88.     public MinimizeCommand() {  
  89.         whObj = new WindowHanlder();  
  90.     }  
  91.       
  92. //命令执行方法,将调用请求接收者的业务方法  
  93.     public void execute() {  
  94.         whObj.minimize();  
  95.     }  
  96. }  
  97.   
  98. //窗口处理类:请求接收者  
  99. class WindowHanlder {  
  100.     public void minimize() {  
  101.         System.out.println("将窗口最小化至托盘!");  
  102.     }  
  103. }  
  104.   
  105. //帮助文档处理类:请求接收者  
  106. class HelpHandler {  
  107.     public void display() {  
  108.         System.out.println("显示帮助文档!");  
  109.     }  
  110. }  

       为了提高系统的灵活性和可扩展性,我们将具体命令类的类名存储在配置文件中,并通过工具类XMLUtil来读取配置文件并反射生成对象,XMLUtil类的代码如下所示:

  1. import javax.xml.parsers.*;  
  2. import org.w3c.dom.*;  
  3. import org.xml.sax.SAXException;  
  4. import java.io.*;  
  5.   
  6. public class XMLUtil {  
  7. //该方法用于从XML配置文件中提取具体类类名,并返回一个实例对象,可以通过参数的不同返回不同类名节点所对应的实例  
  8.     public static Object getBean(int i) {  
  9.         try {  
  10.             //创建文档对象  
  11.             DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();  
  12.             DocumentBuilder builder = dFactory.newDocumentBuilder();  
  13.             Document doc;                             
  14.             doc = builder.parse(new File("config.xml"));   
  15.           
  16.             //获取包含类名的文本节点  
  17.             NodeList nl = doc.getElementsByTagName_r("className");  
  18.             Node classNode = null;  
  19.             if (0 == i) {  
  20.                 classNode = nl.item(0).getFirstChild();  
  21.             }  
  22.             else {  
  23.                 classNode = nl.item(1).getFirstChild();  
  24.             }   
  25.   
  26.             String cName = classNode.getNodeValue();  
  27.               
  28.             //通过类名生成实例对象并将其返回  
  29.             Class c = Class.forName(cName);  
  30.             Object obj = c.newInstance();  
  31.             return obj;  
  32.         }     
  33.         catch(Exception e){  
  34.             e.printStackTrace();  
  35.             return null;  
  36.         }  
  37.     }  
  38. }  

       配置文件config.xml中存储了具体建造者类的类名,代码如下所示:

posted @ 2013-11-12 09:21  Wishmeluck  阅读(277)  评论(0)    收藏  举报