22. 数据结构——职责链模式

“数据结构” 模式

  • 常常有一些组件在内部具有特定的数据结构,如果让客户程序依赖这些特定的数据结构,将极大地破坏组件的复用。这时候,将这些特定的数据结构封装在内部,在外部提供统一的接口,来实现与特定数据结构无关的访问,是一种行之有效的解决方案。
  • 典型模式
    • Composite
    • Iterator
    • Chain of Resposibility

一、场景分析

假设我们要实现一个请假或加薪的申请系统,请假时,如果天数不超过两天,只需要项目经理批准,如果大于2天且不超过5天,就需要总监批准,如果大于5天,就要总经理批准;申请加薪,都需要总经理进行批准。

要实现这个,我们可以首先把申请抽象出一个类

//请求
class Request {
  //申请类别
  public String requestType;
  //申请内容
  public String requestContent;
  //数量
  public int number;
}

然后再写一个管理者类,管理者负责审批

//管理者
class Manager {
  protect String  name;
  public Manager(String name) {
    this.name = name;
  }
  
  public void getResult(String managerLevel, Request request) {
    if(managerLevel == "经理") {
      if(request.requestType == "请假" && request.number <= 2) {
        System.out.println("请假小于2,被批准");
      } else {
        System.out.println("我无权处理");
      }
    }
    else if(managerLevle == "总监") {
      if(reuqest.requestType == "请假" && request.number <= 5) {
        System.out.println("请假小于5,被批准");
      } else {
        System.out.println("我无权处理");
      }
    }
    else if(managerLevel == "总经理") {
      if(request.requestType == "请假") {
        System.out.println("批准");
      } else if(request.requestType == "加薪" && request.number <= 500) {
        System.out.println("批准");
      } else if(request.requestType == "加薪" && request.number > 500) {
        System.out.println("再说吧");
      }
    }
  }
}

上面的这段代码中,getResult方法太长,充斥着“坏代码”的味道,有以下几点:

  1. 员工在提交申请时,必须要知道该申请对应的是哪个级别的管理者;

  2. 如果以后需要添加管理类别,如部门经理、人力总监、副总经理等,那就意味着都要去改变这个类,违反了开放-封闭原则

在这里,管理者类别是变化点,我们可以把它抽象出通用的管理者类,利用多态来化解分支带来的僵化;对于实现经理无权时上报总监,总监无权时在上报总经理这样的功能,我们可以把用户的请求传递,知道解决这个请求为止。

这就是职责链模式的意图了

用职责链模式重构上述的代码

class Manager {
  public Manager superior;
  
  public void setSuppior(Manager superior) {
    this.superior = superior;
  }
  
  pulbic abstract void processRequest(Request request;);
}

class JingLi extends Manager {
    public JingLi(String name) {
        super(name);
    }

    @Override
    public void processRequest(Request request) {
        System.out.printf("请求是%s%d, ", request.requestType, request.number);
        if(request.requestType.equals("请假") && request.number <= 2) {
            System.out.println("被经理批准");
        } else {
            System.out.println("经理无权处理");
            superior.processRequest(request);
        }
    }
}

class ZongJian extends Manager {

    public ZongJian(String name) {
        super(name);
    }
    @Override
    public void processRequest(Request request) {
        System.out.printf("请求是%s%d, ", request.requestType, request.number);
        if(request.requestType.equals("请假") && request.number <= 5) {
            System.out.println("被总监批准");
        } else {
            System.out.println("总监无权处理");
            superior.processRequest(request);
        }
    }
}

客户端的代码如下:

public class ChainOfResponsibility {
    public static void main(String[] args) {
        //定义好组织架构,完全可以根据实际需求来更改设置
        JingLi jingli = new JingLi("经理");
        ZongJian zongjian = new ZongJian("总监");
        ZongJingLi zongjingli = new ZongJingLi("总经理");
        jingli.setSuperior(zongjian);
        zongjian.setSuperior(zongjingli);

      	//客户端的所有申请都是由 "经理" 发起的,但实际谁来决策由具体管理者来处理,客户端并不知道
        Request request1 = new Request();
        request1.requestType = "请假";
        request1.requestContent = "小菜请假";
        request1.number = 1;
        jingli.processRequest(request1);

        Request request2 = new Request();
        request2.requestType = "请假";
        request2.requestContent = "小菜请假";
        request2.number = 3;
        jingli.processRequest(request2);

        Request request3 = new Request();
        request3.requestType = "加薪";
        request3.requestContent = "小菜请求加薪";
        request3.number = 500;
        jingli.processRequest(request3);
    }
}

数出结果是:

请求是请假1, 被经理批准
请求是请假3, 经理无权处理
请求是请假3, 被总监批准
请求是加薪500, 经理无权处理
请求是加薪500, 总监无权处理
请求是加薪500, 总经理批准

通过这种方式,很好地解决了原来大量分支判断造成难维护、灵活性差的问题。

二、动机

使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

三、定义

类图:
在这里插入图片描述

参与者:

  • Handler(如Manager):
    • 定义一个处理请求的接口
    • 实现后继链
  • ConcreteHandler(如JingLi、ZongJingLi):
    • 处理它所负责的请求
    • 如果可处理该请求,就处理之;否则转发给它的后继者
  • Client
    • 向链上的具体处理者对象提交请求

使用场景:

  • 有多个对象可以处理同一个请求,哪个对象处理该请求在运行时刻自动确定
  • 你想在不明确接受者的情况下,想多个对象中的一个提交一个请求
  • 可处理一个请求的对象集合应该被动态指定
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值