实例讲解C#中的职责链模式

2020-07-09 12:01:57王振洲

请假审批系统

请假审批系统提供统一请假申请接口,内部通过请假天数决定哪个审批者参与审批

class VacationApproveSystem
{
  private VacationApprover teamLeader = new TeamLeader();
  private VacationApprover departmentLeader = new DepartmentLeader();
  private VacationApprover boss = new Boss();

  public void HandleVacationRequest(VacationRequest request)
  {
    Console.WriteLine("Now handle {0}'s {1} days' vacation request", request.RequesterName, request.DayNum);

    if (request.DayNum <= teamLeader.DayCanHandle)
    {
      teamLeader.HandleVacationRequest(request);
    }
    else if (request.DayNum <= departmentLeader.DayCanHandle)
    {
      departmentLeader.HandleVacationRequest(request);
    }
    else if (request.DayNum <= boss.DayCanHandle)
    {
      boss.HandleVacationRequest(request);
    }
    else
    {
      Console.WriteLine("Cannot handle this request after all");
    }
  }
}

测试代码

class Program
{
  static void Main(string[] args)
  {
    VacationApproveSystem system = new VacationApproveSystem();

    system.HandleVacationRequest(new VacationRequest() { DayNum = 5, RequesterName = "laohu" });

    system.HandleVacationRequest(new VacationRequest() { DayNum = 10, RequesterName = "laohu" });

    system.HandleVacationRequest(new VacationRequest() { DayNum = 12, RequesterName = "laohu" });
  }
}

结果显示

一切都是正常的,当5天时,部门经理审批,10天时,老板审批,大于10天无人能批。 Good job。

回头看看

实现了第一版代码之后,我们再回过头看看,虽然代码功能无误,但是VacationApproveSystem似乎承担了过多的职责,它不但需要提供统一的请假审批接口给最终用户,它同时还需要知道每个请假审批者能审批的请假天数并在内部实现请假请求转发给不同审批者的逻辑。这样既违反了迪米特法则——它知道的太多了,也违反了开闭原则——如果任何一个审批者修改了自身能审批的请假天数,这个类都会被波及,最后,它还违反了单一职责——一个类只能有一个引起变化的原因。

有鉴于此,我们这版代码只能算凑合用,但远远谈不上结构良好,老老实实地重构代码吧,下面请出我们今天的主角。

职责链模式

解耦具体对象和请求,使得多个对象都有机会处理请求。将对象连成一条链,沿着链传递请求直到有对象处理它

乍一听有点生涩,翻译一下就是

解耦具体对象和请求——不要预先指定哪个对象来处理此请求(因为很多时候并不知道) 使多个对象都有机会——有一众候选对象,具体使用哪个对象是在运行时决定的 连成链传递请求——像链表一样,要在对象中体现出对象之间的链关系,而不要通过其他类以if..else的方式实现