1,问题定义
客户端发起一个请求,会有多个对象来处理,将处理对象连成一个“链”,这个链可认为是“处理流程”,链上的每个处理对象有不同的处理逻辑,由链上的符合条件的对象来处理。这么做的好处是:请求和处理对象解耦,处理流程可以变换,处理对象可替换。
2,实现步骤
定义一个处理请求的抽象类,定义处理请求的抽象方法,定义一个可以设置另一个处理对象的方法(即链上的下一个处理节点)。
示例代码(假设情景:员工向领导申请经费,不同级别的领导有不同的最高限额授权,处理流程为先给项目经理,再给部门经理,最后给总经理)
/**
* 处理请求的抽象类
* @author Abner
*
*/
abstract class Handler{
protected Handler handler = null;
/**
* 用于接收职责链上的下一个处理节点
* @param handler
*/
public void setHandler(Handler handler){
this.handler = handler;
}
/**
* 处理请求的业务方法
* @param user
* @param fee
* @return
*/
protected abstract String handleRequest(String user,double fee);
}
/**
* 具体的请求处理类,项目经理
* @author Abner
*
*/
class ProjectManager extends Handler{
@Override
protected String handleRequest(String user, double fee) {
String str = "";
if(fee <= 500){
if("小张".equals(user)){
str = "项目经理允许 "+user+" 申请的经费 "+fee;
}else{
str = "项目经理不允许 "+user+" 申请的经费 "+fee;
}
}else{
if(this.handler != null){
str = this.handler.handleRequest(user, fee);
}
}
return str;
}
}
/**
* 具体的请求处理类,部门经理
* @author Abner
*
*/
class DepartmentManager extends Handler{
@Override
protected String handleRequest(String user, double fee) {
String str = "";
if(fee <= 1000){
if("小张".equals(user)){
str = "部门经理允许 "+user+" 申请的经费 "+fee;
}else{
str = "部门经理不允许 "+user+" 申请的经费 "+fee;
}
}else{
if(this.handler != null){
str = this.handler.handleRequest(user, fee);
}
}
return str;
}
}
/**
* 具体的请求处理类,总经理
* @author Abner
*
*/
class GeneralManager extends Handler{
@Override
protected String handleRequest(String user, double fee) {
String str = "";
if("小张".equals(user)){
str = "总经理允许 "+user+" 申请的经费 "+fee;
}else{
str = "总经理不允许 "+user+" 申请的经费 "+fee;
}
return str;
}
}
public static void main(String[] args) {
Handler hg = new GeneralManager();
Handler hd = new DepartmentManager();
Handler hp = new ProjectManager();
hd.setHandler(hg);
hp.setHandler(hd);
p(hp.handleRequest("小张", 300));
p(hp.handleRequest("小李", 300));
p(hp.handleRequest("小张", 800));
p(hp.handleRequest("小李", 800));
p(hp.handleRequest("小张", 1200));
p(hp.handleRequest("小李", 1200));
}
static void p(String s){
System.out.println(s);
}
输出
项目经理允许 小张 申请的经费 300.0
项目经理不允许 小李 申请的经费 300.0
部门经理允许 小张 申请的经费 800.0
部门经理不允许 小李 申请的经费 800.0
总经理允许 小张 申请的经费 1200.0
总经理不允许 小李 申请的经费 1200.0
3,认识职责链
3.1,如何构建链
按照实现的地方可以分为:在客户端发出请求前,组合职责链,称为外部链。在Handler里面实现链的组合,称为内部链。在处理对象中,这要求处理对象不仅要处理业务,还要对整个业务流程熟悉。
3.2,谁来处理
由职责链中符合条件的那个对象处理,如果该请求被处理了,那请求就到处为止。如果整个链中没有合适的对象,那该请求就不会被处理了。
3.3,处理多种请求
设计时应该考虑到未来功能的扩展,比如会有多种请求。对于多种请求,可以在接口中分别定义多个方法,每种方法对应一种请求,但这种方式的缺点是每次扩展业务,都需要改接口,而且接口对应的实现类也需要改,这种方式不靠谱。另外的方式是,在接口中定义一个“通用”的方法用来处理请求,不论什么样的请求都用这个方法,将请求的业务参数封装到一个专门的请求类中,在类中定义请求的类型,在接口的实现类中针对不同类型的请求实现不同,当新增请求类型了,那就写一个之前的接口实现类的子类,在子类中重写业务方法。
示例:
当只有一个业务类型时
/**
* 处理请求的抽象类
* @author Abner
*
*/
abstract class Handler{
protected Handler handler = null;
/**
* 用于接收职责链上的下一个处理节点
* @param handler
*/
public void setHandler(Handler handler){
this.handler = handler;
}
/**
* 处理请求的业务方法
* @param user
* @param fee
* @return
*/
protected abstract String handleRequest(Request request);
}
/**
* 具体的请求处理类,项目经理
* @author Abner
*
*/
class ProjectManager extends Handler{
@Override
protected String handleRequest(Request request) {
String str = "";
if(request.getType() == Request.FOOD_FEE){
if(request.getFee() <= 500){
if("小张".equals(request.getUser())){
str = "项目经理允许 "+request.getUser()+" 申请的经费 "+request.getFee();
}else{
str = "项目经理不允许 "+request.getUser()+" 申请的经费 "+request.getFee();
}
}else{
if(this.handler != null){
str = this.handler.handleRequest(request);
}
}
}
return str;
}
}
/**
* 具体的请求处理类,部门经理
* @author Abner
*
*/
class DepartmentManager extends Handler{
@Override
protected String handleRequest(Request request) {
String str = "";
if(request.getType() == Request.FOOD_FEE){
if(request.getFee() <= 1000){
if("小张".equals(request.getUser())){
str = "部门经理允许 "+request.getUser()+" 申请的经费 "+request.getFee();
}else{
str = "部门经理不允许 "+request.getUser()+" 申请的经费 "+request.getFee();
}
}else{
if(this.handler != null){
str = this.handler.handleRequest(request);
}
}
}
return str;
}
}
/**
* 具体的请求处理类,总经理
* @author Abner
*
*/
class GeneralManager extends Handler{
@Override
protected String handleRequest(Request request) {
String str = "";
if(request.getType() == Request.FOOD_FEE){
if("小张".equals(request.getUser())){
str = "总经理允许 "+request.getUser()+" 申请的经费 "+request.getFee();
}else{
str = "总经理不允许 "+request.getUser()+" 申请的经费 "+request.getFee();
}
}
return str;
}
}
/**
* 请求类,封装了请求数据
* @author Abner
*
*/
class Request{
public static int FOOD_FEE = 1;
public static int TRAVEL_FEE = 2;
int type;
String user;
double fee;
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public double getFee() {
return fee;
}
public void setFee(double fee) {
this.fee = fee;
}
}
当增加了需求
class ProjectManager2 extends ProjectManager{
@Override
protected String handleRequest(Request request) {
String str = "";
if(request.getType() == Request.TRAVEL_FEE){ //新的业务需求
if(request.getFee() <= 500){
str = "项目经理同意 "+request.getUser()+" 差旅费申请 "+request.getFee();
}else{
if(this.handler != null){
str = this.handler.handleRequest(request);
}
}
}else{ //其他的需求交给父类处理
str = super.handleRequest(request);
}
return str;
}
}
class GeneralManager2 extends GeneralManager{
@Override
protected String handleRequest(Request request) {
String str = "";
if(request.getType() == Request.TRAVEL_FEE){ //新的业务需求
if(request.getFee() <= 5000){
str = "总经理同意 "+request.getUser()+" 差旅费申请 "+request.getFee();
}else{
if(this.handler != null){
str = this.handler.handleRequest(request);
}
}
}else{ //其他的需求交给父类处理
str = super.handleRequest(request);
}
return str;
}
}
class DepartmentManager2 extends DepartmentManager{
@Override
protected String handleRequest(Request request) {
String str = "";
if(request.getType() == Request.TRAVEL_FEE){ //新的业务需求
if(request.getFee() <= 1000){
str = "部门经理同意 "+request.getUser()+" 差旅费申请 "+request.getFee();
}else{
if(this.handler != null){
str = this.handler.handleRequest(request);
}
}
}else{ //其他的需求交给父类处理
str = super.handleRequest(request);
}
return str;
}
}
客户端调用
public static void main(String[] args) {
Handler hg = new GeneralManager2();
Handler hd = new DepartmentManager2();
Handler hp = new ProjectManager2();
hd.setHandler(hg);
hp.setHandler(hd);
Request req = new Request();
req.setFee(200);
req.setType(Request.FOOD_FEE);
req.setUser("小丽");
System.out.println(hp.handleRequest(req));
Request req2 = new Request();
req2.setFee(2000);
req2.setType(Request.TRAVEL_FEE);
req2.setUser("小五");
System.out.println(hp.handleRequest(req2));
}
输出
项目经理不允许 小丽 申请的经费 200.0
总经理同意 小五 差旅费申请 2000.0
这种方式的缺点是,客户端得知道每种类型的请求对应的业务处理类型,还有,没增加一种请求都写一个新的子类,要么类层次过多,要么粒度太细。
3.4,功能链
标准的职责链是当请求被链中的一个节点处理后,整个流程就结束了。现在扩展下,可以将业务中一系列功能拆分成多个步奏,每个步奏都封装在一个处理节点里,处理流程的要从头走到尾才结束。与web中的Filter类似,过了一个Filter,过另一个Filter,直到结束。
所谓职责链,不过是将一系列操作,这些可能是平行的(标准的职责链),也可能是相互依赖的(功能链),将其他分离出来,抽象一个统一的接口,每步操作都实现这个接口,并且提供将这些步骤连接起来的方式。由此获得的好处是,这些操作的顺序可以动态的组合(当业务流程变化时),当其中某个操作需要修改或替换时,也很容易可以实现。(分离职责,动态组合)