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

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

所以,这么看来这个模式和我们的例子简直是绝配,我们已经做了大部分的工作了,现在剩下的就只是修改审批者,让审批者能链起来 

代码重构

修改请假审批基类
最重要的改动,就是修改基类,让对象能链起来,在VacationApprover中添加一个后继节点和一个设置后继节点的方法。同时在基类的审批方法中,完成请求传递,即,如果请假申请超过了当前审批人的能力范围,则转发至后继节点。修改后的类如下

abstract class VacationApprover
{
  private VacationApprover nextVacationApprover = null;

  public void SetNextVacationApprover(VacationApprover approver)
  {
    nextVacationApprover = approver;
  }

  protected VacationApprover(int dayCanHandle)
  {
    DayCanHandle = dayCanHandle;
  }

  public int DayCanHandle { get; protected set; }

  public void HandleVacationRequest(VacationRequest request)
  {
    if (request.DayNum <= DayCanHandle)
    {
      DoHandleVacationRequest(request);
    }
    else
    {
      if(nextVacationApprover != null)
      {
        nextVacationApprover.HandleVacationRequest(request);
      }
      else
      {
        Console.WriteLine("Cannot handle this request after all");
      }
    }
  }

  protected abstract void DoHandleVacationRequest(VacationRequest request);
}

修改请假审批系统

基类重构结束之后,请假审批系统就可以瘦身了,删除了所有判断逻辑,仅仅在构造函数里面完成链组建的工作,接着一键调用,齐活。

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

  public VacationApproveSystem()
  {
    teamLeader.SetNextVacationApprover(departmentLeader);
    departmentLeader.SetNextVacationApprover(boss);
  }

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

    teamLeader.HandleVacationRequest(request);
  }
}

测试

其他请假审批子类和测试客户端都不需要改动,这次重构工作量非常小,运行代码,一切正常,重构成功。

总结

这就是职责链模式的使用。和状态模式有点像,解决了以下问题:

通过添加子类把一些逻辑判断从调用类(VaccationApproveSystem)移到子类的方式,使得调用类满足迪米特法则 想在职责链上面添加更多节点的时候,只需要添加新类和修改链组装部分的代码,基本满足开闭原则(这里几乎不可能完全满足开闭原则,毕竟有修改就意味着我们肯定会改动VaccationApproveSystem类,只是我们应该尽量的让代码改动量少,以提高控制代码变动的能力)

和状态模式一样,它也有子类爆炸的风险。