IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope: Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  WebSphere | Lotus | Java technology  >

developerWorks 图书频道: 西游记、设计模式与 IBM WebSphere Portal 应用开发,第 7 章

行为模式之责任链模式(Responsibility Chain)

developerWorks
文档选项

未显示需要 JavaScript 的文档选项


级别: 初级

王 立, 软件工程师, IBM
郑 长庆, 软件工程师, IBM
陈 喜伦, 软件工程师, IBM
闫 志东, 软件工程师, IBM

2009 年 5 月 26 日

本书借助《西游记》中众多耳熟能详的小故事,以借喻的手法阐释了《设计模式》一书中所阐述的 23 个设计模式的精髓。同时还提供了详细的 Java Portlet 规范 1.0 的中文译本供读者学习参考,并指导用户基于 IBM WebSphere Portal 开发功能丰富多样的 Portal 应用,使读者在熟悉 IBM WebSphere Portal 应用开发的同时,进一步理解设计模式。

在此我们推出了本书的第 347 章供大家在线浏览。更多推荐书籍请访问 developerWorks 图书频道

图书信息 书名:西游记、设计模式与IBM WebSphere Portal应用开发
作者:王立、郑长庆、陈喜伦、闫志东 编著
出版社:电子工业出版社
出版日期:2009 年 1 月
ISBN:978-7-121-07172-0
购买: 中国互动出版网当当网卓越网

推荐章节:

更多推荐书籍,请访问 developerWorks 图书频道

欢迎您对本书提出宝贵的反馈意见。您可以通过本页面最下方的 建议 栏目为本文打分,并反馈您的建议和意见。

如果您对 developerWorks 图书频道有什么好的建议,欢迎您将建议发给我们

7.1.1 概述

责任链模式用于弱化请求发生者和请求处理者之间的关系。当多个对象都可以对请求进行处理,但不同的对象能处理的请求类型不同时,可以通过指向另一个对象的引用把这些对象连成一条责任链。当 Client 发出一个请求时,并不知道具体由哪个对象进行处理,它看到的只是一条责任链,将请求直接交给责任链,请求会在责任链中传递,直到找到一个能够进行处理的对象或者遍历结束找不到一个能够处理的对象为止。

Java 语言中的异常处理机制就是责任链模式的一个典型应用例子。可能抛出异常的语句由 try-catch 包围,在 try-catch 中指定能处理的异常类型。当一个 Java 异常产生时,由包围产生异常的语句的最里层的 try-catch 进行处理,如果该层 try-catch 不能处理,则继续将异常抛向上一层的 try-catch 处理,最终直到 main 函数中如果还没有相应的 try-catch 处理,则 Java 程序打印出异常信息,Java 虚拟机也同时结束运行。

图 7-1 描述了责任链模式的基本组成。


图 7-1. 责任链模式类图
图 7-1. 责任链模式类图

 Handler:定义请求处理的接口,并定义指向下一个请求处理对象的引用。

 ConcreteHandler:从抽象请求处理者派生,并实现具体的请求处理方法。





回页首


7.1.2 寻例西游

话说孙悟空在五庄观偷吃人参果,推倒人参树,被镇元子捉住师徒四人,要为树报仇。为救师父师弟,悟空和镇元子讲好,若医活树,就可放了师父师弟,两家才得安宁。因此,悟空遍游仙境,四处寻方。第二十六回 孙悟空三岛求方 观世音甘泉活树 中写道:

……行者道:“……有甚医树的方儿,传我一个,急救唐僧脱苦。”(福禄寿)三星闻言,心中也闷道:“……那人参果乃仙木之根,如何医治?没方,没方。”
……行者道:“……特来尊处求赐一方医治,万望慨然。”(东华大)帝君道:“……人参果又是开天地辟之灵根,如何可治!无方!无方!”
……行者将那医树求方之事,具陈了一遍。(瀛洲)九老也大惊道:“你也忒惹祸!惹祸!我等实是无方。”
……行者再拜道:“……弟子因此志心朝礼,特拜告菩萨。伏望慈悯,俯赐一方,以救唐僧早早西去。”……菩萨道:“我这净瓶底的‘甘露水’,善治得仙树灵苗。”
……

可以看出,孙悟空(包括镇元子)作为请求发起者,发出了医活人参树的请求。虽然知道“方从海上来”,但并不知道哪位神仙(对象)能够医活仙树(处理请求)。因此“医树”的请求在蓬莱三星、方丈仙山帝君、瀛洲九老和落伽山观音菩萨这个责任链中传递,最后终于在观音菩萨处求得‘甘露水’医树(找到了处理请求的对象)。





回页首


7.1.3 典型应用

考虑在一个公司中,不同角色的人员能够处理的 Request 的级别不同,Manager 只能处理一般的 Request,Director 具有更高的权限,能够审批更高级别的 Request,CEO 能处理的 Request 级别还要高些。

Employee 代表一个抽象员工。属性 requestLevel 定义了一个员工能处理的请求类型。属性 boss 指向自己的上级老板。方法 handle 用于处理请求,具体的员工类必须覆盖该方法,如果具体的员工类不能处理某个请求,则通过调用父类 Employee 的 handle 方法将请求交给上级老板处理。


代码清单 7-1. Employee 类
				
 package com.ibm.designpattern.chap7.responsiblitychain; 

 abstract public class Employee { 
    protected Person boss; 
    protected String name; 
    protected int requestLevel; 
    
    public Employee (String name, Employee boss) { 
        this.name = name; 
        this.boss = boss;   
    } 
    
    public String getName() { 
    	 return name; 
    } 
    
    public void handle(Request request) { 
        if (boss != null) { 
        	 boss.handle(request); 
        } else { 
        	 System.out.println("Nobody can handle the request."); 
        } 
    } 
 }

Manager 是一个具体员工类,覆写了父类的 handle 方法,先对请求的类型进行判断,如果是能接受的类型则进行处理,否则通过父类的 handle 方法交给上级老板处理。 Director 和 CEO 同 Manager 类似,都是具体的员工类,只是能处理的请求类型不同。


代码清单 7-2. Manager 类
				
package com.ibm.designpattern.chap7.responsiblitychain; 

public class Manager extends Employee { 
    public Manager(String name, Person boss) { 
        super(name, boss); 
        requestLevel = 1; 
    } 

    public void handle(Request request) { 
        if (requestLevel >= request.getType()) { 
            System.out.println(name 
                + "(Manager) says: I can handle the request"); 
        } else { 
            System.out.println(name 
                + "(Manager) says: I can not handle the request. My boss " 
                + boss.getName() + " will handle it."); 
            super.handle(request); 
        } 
    } 
}


代码清单 7-3 Director 类
				
package com.ibm.designpattern.chap7.responsiblitychain; 

public class Director extends Employee { 
    public Director(String name, Person boss) { 
        super(name, boss); 
        requestLevel = 2; 
    } 

    public void handle(Request request) { 
        if (requestLevel >= request.getType()) { 
            System.out 
                .println(name + "(Director) says: I can handle the request"); 
        } else { 
            System.out.println(name 
                + "(Director) says: I can not handle the request. My boss " 
                + boss.getName() + " will handle it."); 
            super.handle(request); 
        } 
    } 
}


代码清单 7-4. CEO 类
				
package com.ibm.designpattern.chap7.responsiblitychain; 

public class CEO extends Employee { 
    public CEO (String name, Person boss) { 
        super(name, boss); 
        requestLevel = 3; 
    } 

    public void handle(Request request) { 
        if (requestLevel >= request.getType()) { 
            System.out.println(name + "( CEO) says: I can handle the request"); 
        } else { 
            System.out.println(name 
                    + "( CEO) says: I can not handle the request. My boss " 
                    + boss.getName() + " will handle it."); 
            super.handle(request); 
        } 
    } 
}

Request 封装了一个请求,由于程序只是演示作用,仅有类型一个属性。


代码清单 7-5. Request 类
				
package com.ibm.designpattern.chap7.responsiblitychain; 

public class Request { 
    public static final int REQUEST_1 = 1; 
    public static final int REQUEST_2 = 2; 
    public static final int REQUEST_3 = 3; 
    
    private int type; 
    
    public Request(int type) { 
        this.type = type; 
    } 
    
    public int getType() { 
        return type;   
    } 
}

Client 演示了上述几个不同的员工类如何通过责任链模式进行请求处理和传递。


代码清单 7-6. 责任链使用者
				
package com.ibm.designpattern.chap7.responsiblitychain; 

class Client { 
    public static void main(String args[]) { 
        Employee ceo = new CEO("Tom", null); 
        Employee director = new Director("Mike", ceo); 
        Employee manager = new Manager("Jack", director); 
        
        Request req1 = new Request(Request.REQUEST_1); 
        Request req2 = new Request(Request.REQUEST_2); 
        Request req3 = new Request(Request.REQUEST_3); 
        
        System.out.println("Submit req1 to manager");        
        manager.handle(req1); 
        System.out.println(); 
        System.out.println("Submit req2 to manager"); 
        manager.handle(req2); 
        System.out.println(); 
        System.out.println("Submit req3 to manager"); 
        manager.handle(req3); 
    } 
}

程序运行结果如图 7-2 所示。


图 7-2. 责任链模式运行结果
				
Submit req1 to manager 
Jack(Manager) says: I  can handle the request 

Submit req2 to manager 
Jack(Manager) says: I can not handle the request. My boss Mike will handle it. 
Mike(Director) says: I can handle the request 

Submit req3 to manager 
Jack(Manager) says: I  can not handle the request. My boss Mike will handle it. 
Mike(Director) says: I can not handle the request. My boss Tom will handle it. 
Tom(VP) says: I can handle the request





回页首


7.1.4 Portal 应用

在我们的 Portal 应用实例中,用户管理模块实现体现了责任链模式,用户管理包括增加、删除用户,验证用户信息的有效性,验证用户的登录信息等。这些不同的用户操作用不同的类进行封装,并组成一个责任链。责任链节点在处理用户请求时,从 request 中取出用户管理的命令,如果是其能处理的用户管理命令则进行相应的操作,如果不能则传给下一个责任链节点处理。

ActionRequestProcessChain 定义了责任链接口,addChain 用于指定与之关联的下一个责任链节点,handleRequest 对请求处理,getNextChain 返回下一个责任链节点。


代码清单 7-7. ActionRequestProcessChain 接口
				
package com.ibm.journeywest.web.portlet; 

import javax.portlet.ActionRequest; 
import javax.portlet.ActionResponse; 

/** 
* 动作请求处理链接口
* 
* @author Yan Zhi Dong yanzhid@cn.ibm.com 
* 
*/ 
public interface IActionRequestProcessChain { 
     /** 
     * 增加一个动作请求处理链结点
     * 
     * @param chain 
     */ 
     void addChain(IActionRequestProcessChain chain); 

     /** 
     * 处理请求
     * 
     * @param request 
     *            ActionRequest 对象
     * @param response 
     *            ActionResponse 对象
     */ 
     void handleRequest(ActionRequest request, ActionResponse response); 

     /** 
     * 获得下一个链结点
     * 
     * @return 下一个链结点
     */ 
     IActionRequestProcessChain getNextChain(); 
}

在 UserManagementPortlet 中,init 方法将负责构造用户管理的责任链,在方法 processAction 中调用责任链,对用户请求进行处理。用户管理责令链由 3 个节点构成, CheckUserChain 检查用户的有效性 CheckUserInputChain 负责检查输入的用户信息有效性,OperateUserInformationChain 负责添加删除用户,关于这 3 个责任链节点类的详细代码在此不作展示,请参考本书所附光盘。 processAction 方法则将请求交给责任链进行处理


代码清单 7-8. UserManagementPortlet 类
				
package com.ibm.journeywest.web.portlet; 

import …

/** 
* 用户管理 portlet 
* 
* @author Yan Zhi Dong yanzhid@cn.ibm.com 
* 
*/ 
public class UserManagementPortlet extends javax.portlet.Generic Portlet { 
     private ActionRequestProcessChain actionRequestProcessChain = null; 

     public void init() throws PortletException { 
         super.init(); 
 // 构造链表
         actionRequestProcessChain = new CheckRequestUserChain(); 
         IActionRequestProcessChain checkUserInputChain = new CheckUserInputChain(); 
         IActionRequestProcessChain checkUserChain = new CheckUserChain(); 
         IActionRequestProcessChain operateUserInformationChain = 
             new OperateUserInformationChain(); 
         actionRequestProcessChain.addChain(checkUserInputChain); 
         checkUserInputChain.addChain(checkUserChain); 
         checkUserChain.addChain(operateUserInformationChain); 
     } 
     …
public void processAction(ActionRequest request, ActionResponse response) 
             throws PortletException, java.io.IOException { 
         ActionRequestWrapper requestWrapper = new ActionRequest Wrapper(request); 
         // 请求流经链
         actionRequestProcessChain.handleRequest(requestWrapper, response); 
         response.setRenderParameter("COMMAND", request.getParameter ("COMMAND")); 
     } 
}





回页首


7.1.5 小结

责任链模式在请求 - 处理程序中,弱化了二者之间的关联,降低了请求发生者和请求处理者之间的耦合程度,请求发生者无需知道一个请求具体由哪个对象进行处理,只是把请求交给责任链。同时这也使得程序中责任划分更加的细化,每个请求处理者对象只有一种职责,只能处理对应类型的请求,这符合面向对象的设计原则,不同的请求处理对象之间只是通过一个引用进行关联。

同时责任链模式也会带来一些缺点,首先,请求不能保证都能被处理,如果在责任链中找不到一个合适的请求处理对象,则请求不能被处理。其次,请求处理的速度可能相对较慢,由于请求发生者并不知道请求具体应该交给哪个请求处理对象处理,请求需要在责任链中遍历,直到找到一个合适的请求处理对象。

上述例子描述的是一种典型的直线型责任链,但在具体的应用中可以对责任链的具体实现进行扩展,在一些复杂的应用中,责任链还可以是树形(如图 7-3 所示),图形,甚至是环形链等,这些都和具体应用相关,同一个请求的不同部分甚至可以分别由责任链中的不同对象进行处理(如图 7-4 所示)。


图 7-3. 树形责任链图
图 7-3. 树形责任链图

图 7-4. 复杂请求责任链
图 7-4. 复杂请求责任链




回页首


7.1.6 IBM 小故事- IBM 和阿波罗登月计划

1969 年 7 月 20 日美国东部时间 16 时 17 分,美国“阿波罗 11 号”飞船的登月舱和着陆设备在月球表面着陆。 22 时 56 分,宇航员阿姆斯特朗率先踏上月球荒凉沉寂的土地,成为登上月球的第一人。阿姆斯特朗在踏上月球时所说的名言:“对一个人来说 , 这只是小小的一步 , 但对全人类来说 , 这却是巨大的飞跃”,深刻地道出了这次登月活动在人类科学技术历史上的重要地位。


图 7-5. 宇航员登上月球
图 7-5. 宇航员登上月球

可能很少人知道,这次人类成功登上月球的壮举也有 IBM 的一份功劳。作为登月计划一部分,IBM 一台计算机在轨天文台二号”(Orbiting Astronomical Observatory II)上工作了整整一年。除此之外,IBM 的计算机还被大量用于美国随后的阿波罗登月计划和其它太空研究中:

1970 年,IBM 公司生产的计算机协助飞行控制人员成功援救了“阿波罗 13 号”宇宙飞船上的宇航员。

1971 年,IBM 公司生产的计算机引导“阿波罗 14 号”和“阿波罗 15 号”宇宙飞船成功登月,并大大提高了第一艘进入火星轨道的“水手 9 号”宇宙飞船拍摄的火星照片的精度。

1972 年,IBM 公司的月球轨道实验团队因在“阿波罗 15 号”登月任务期间对于月球科学的研究出色,获得了美国国家航空与航天局颁发的突出贡献奖。这一年,IBM 公司的人员与产品还对“阿波罗 16 号”和“阿波罗 17 号”最后两次登月任务提供了支持。

1981 年,IBM 又帮助哥伦比亚号航天飞机成功地飞上了天空。



读者反馈

欢迎您对本书提出宝贵的反馈意见。您可以通过本页面最下方的 建议 栏目为本文打分,并反馈您的建议和意见。

如果您对 developerWorks 图书频道有什么好的建议,欢迎您将建议发给我们



参考资料



作者简介

王立,2005 年毕业于西安交通大学计算机科学与技术系,获博士学位。先后参与过 IBM Lotus 和 Rational 产品线的相关开发工作。目前服务于 IBM 中国系统与技术中心,从事软件开发过程与企业级协作方面的研发工作。


郑长庆,2005 年毕业于浙江大学计算机应用专业,获硕士学位。从事 iSeries上IBM Workplace, WebSphere Portal 等相关产品工作。目前主要从事 IBM iSeries Web Administrator 开发。对 J2EE, Web Services, SOA 及 System i 等相关技术感兴趣。


陈喜伦,西安交通大学计算机软件与理论专业硕士。从事 IBM Workplace, WebSphere Portal 等产品相关工作。目前从事针对中小企业的 VoIP Solution 的开发工作,对 J2EE、Eclipse、软件设计、面向对象、设计模式、极限编程和敏捷开发等技术和方法感兴趣。


闫志东,2007 年毕业于南开大学计算机软件与理论专业,获硕士学位。主要从事 IBM Rational 解决方案的设计开发工作。对 J2EE, Java, C/C++ 和 Windows, Linux 软件开发均有兴趣。




对本文的评价








IBM 公司保留在 developerWorks 网站上发表的内容的著作权。未经IBM公司或原始作者的书面明确许可,请勿转载。如果您希望转载,请通过 提交转载请求表单 联系我们的编辑团队。
    关于 IBM 隐私条约 联系 IBM 使用条款