Chain of Responsibility_职责链模式的定义:
使多个对象都有机会去处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
应用Chain of Responsibility_职责链模式解决问题的思路:
我们来设想一个申请聚餐费用的应用,不同的管理者拥有不同的金额额度权限。从项目经理->部门经理->总经理依次拥有的额度是499->999->无限。客户端的申请就在这个链中传递,直到有相关领导处理为止。传统的面向过程的解决方法,自然是在一个函数里不断IF ELSE来判断,并且把整体链条的逻辑处理都封装在一起。这样所有的逻辑和业务对象都耦合在了一起,十分不方便业务的修改和扩充。
要让处理请求的流程可以灵活的变动,一个基本的思路就是动态的构建流程步骤,这样随时都可以重新组合新的流程来。而要让处理请求也要很灵活,那就要让它足够简单,最好是只实现单一的功能,或者有限的功能,这样更有利于修改和复用。
职责链模式的结构:
Handler:定义职责的接口,通常在这里定义处理请求的方法,可以在这里实现后继链
ConcreteHandler:实现职责的类,在这个类中,实现对在它职责范围内请求的处理,如果不处理,就继续转发给请求的后继者
Client:职责链的客户端,向链上的具体处理对象提交请求,让职责链负责处理。
注意:在基本的模式结构上,职责链模式的架构和装饰模式是一模一样的。但是从定义上看,装饰模式,更专注于解耦平行的功能之间的功能,每一个被装载的装饰类都会对需要被处理的类即被装饰类都进行操作。并且装饰模式的各个装饰类之间最好是没有顺序关系的,即谁先装饰谁后装饰没有关系。而职责链模式在每个职责类中需要对自身职责做出判断,不一定对业务进行处理,而是分发给其他有权责的对象处理。
简单的说装饰类模式的每一个加入的装饰类都会对被装饰类起作用。而职责链模式的每个职责类不一定都会对业务对象进行处理,而是进行分发。
我们来看看具体的实现:
successor = $successor; } /** * 处理聚餐费用的申请 * @param user 申请人 * @param fee 申请的钱数 * 成功或者失败的具体通知 */ abstract public function handleFeeRequest($user,$fee);}class ProjectManager extends Handler{ public function handleFeeRequest($user, $fee){ //项目经理权限比较小,只能在500以内 if($fee < 500){ //为了测试,简单点,只同意小李的 if($user === 'xl'){ $str = "项目经理同意".$user."聚餐经费".$fee."元的请求"; } else { //其他人一律不同意 $str = "项目经理不同意".$user."聚餐经费".$fee."元的请求"; } return $str; } else{ //超过500,该对象没有权限了,让职责级别更高的对象来处理 echo 222; if($this->successor != null){ return $this->successor->handleFeeRequest($user,$fee); } } }}class DepManager extends Handler{ public function handleFeeRequest($user, $fee){ //部门经理的权限,只能在1000以内 if($fee < 1000){ //为了测试,简单点,只同意小李的 if($user === 'xl'){ $str = "部门经理同意".$user."聚餐经费".$fee."元的请求"; } else { //其他人一律不同意 $str = "部门经理不同意".$user."聚餐经费".$fee."元的请求"; } return $str; } else{ if($this->successor != null){ return $this->successor->handleFeeRequest($user,$fee); } } }}class GeneralManager extends Handler{ public function handleFeeRequest($user, $fee){ //总经理的权限 echo 333; if($fee >= 1000){ //为了测试,简单点,只同意小李的 if($user === 'xl'){ $str = " 总经理同意".$user."聚餐经费".$fee."元的请求"; } else { //其他人一律不同意 $str = "总经理不同意".$user."聚餐经费".$fee."元的请求"; } return $str; } else{ if($this->successor != null){ return $this->successor->handleFeeRequest($user,$fee); } } }}/** * 让我们看看如何使用 */$h1 = new GeneralManager();$h2 = new DepManager();$h3 = new ProjectManager();$h3->setSuccessor($h2);$h2->setSuccessor($h1);echo $ret1 = $h3->handleFeeRequest('xl', 499);echo $ret2 = $h3->handleFeeRequest('xl', 999);echo $ret3 = $h3->handleFeeRequest('xl', 1000);?>