包装责任链功能是否比直接在 class 中更好?

Is it better to wrap chain of responsibility functionality than have it directly in a class?

我一直专注于学习编程原则和模式,但我发现的责任链示例似乎都与其他示例相矛盾 principles/patterns。将 sethandler 和 nexhandler 直接放置在 class 中会做更多的事情,这似乎是一个非常非常糟糕的主意。

在尝试学习以前的模式时,我确实发现了很多不切实际的简单示例,所以起初我认为我找到的示例就是这种情况。但是经过大量谷歌搜索后,我找不到任何接近我想象的例子。因此,我开始查看文章,但我什至找不到关于处理程序功能应如何与使用它的 class 分开的简短句子。

这让我想到也许在具体的 class 上建立责任链并不是什么大不了的事,因为它只有两种方法。

但是,这似乎真的是错误的。如果您想在其他地方以非责任链模式的方式使用 class,您会怎么做,因为责任链功能直接内置于 class.

在浏览了一页又一页关于责任链的 google 篇文章后,我没有找到关于这个主题的任何内容,我最终找到了一个使用包装器 class 实现功能的示例。它几乎将具体的 class 委托给包装器 class 以便仍然可以使用具体的 class 而无需责任链功能。

所以我的问题是.. 大多数现实世界中责任链原则的实施会使用包装器 class 还是直接在 class 中?也许我只是误解了这种模式实际使用的情况?

为了真正能够比较和理解每种方法,我决定使用这两种方法编写自己的示例。下面我粘贴了两者最重要的部分并链接到完整的示例。

Normal Method

ILoanApprover

interface ILoanApprover{
  public void approveLoan(Loan loan);
  public void setNextApprover(ILoanApprover nextApprover);
}

员工

abstract class Employee implements ILoanApprover{
  protected ILoanApprover nextApprover;
  protected int approvalLimit;
  private String rank;

  public Employee(String rank, int approvalLimit){
    this.rank = rank;
    this.approvalLimit = approvalLimit;
  }

  @Override
  public void setNextApprover(ILoanApprover nextApprover){
    this.nextApprover = nextApprover;
  }
  @Override
  public void approveLoan(Loan loan){

    if (approvalLimit > loan.getAmount() ){
      System.out.println(rank+" approves loan of "+loan.getAmount());
      return;
    }
    nextApprover.approveLoan(loan);
  }
}

经理

class Manager extends Employee{
  public Manager(){
    super("Manager", 5000);
  }
}

贷款

class Loan{
  private int amount;
  public Loan(int amount){
    this.amount = amount;
  }
  public int getAmount(){ return amount; }
}

Wrapper Method

ILoanApprover

interface ILoanApprover{
  public boolean approveLoan(Loan loan);
}

ILoanHandler

interface ILoanHandler{
  public void setNextLoanHandler(ILoanHandler nextHandler);
  public void handleLoanApproval(Loan loan);
}

贷款处理程序

class LoanHandler implements ILoanHandler{

  protected ILoanApprover approver;
  protected ILoanHandler nextHandler;

  public LoanHandler(ILoanApprover approver){
    this.approver = approver;
  }

  @Override
  public void setNextLoanHandler(ILoanHandler nextHandler){
    this.nextHandler = nextHandler;
  }

  @Override
  public void handleLoanApproval(Loan loan){

    boolean approved = approver.approveLoan(loan);

    if (!approved && nextHandler != null){
      nextHandler.handleLoanApproval(loan);
    }
  }
}

员工

abstract class Employee implements ILoanApprover{
  protected int approvalLimit;
  private String rank;
  public Employee(String rank, int approvalLimit){
    this.rank = rank;
    this.approvalLimit = approvalLimit;
  }

  @Override
  public boolean approveLoan(Loan loan){

    if (approvalLimit > loan.getAmount() ){
      System.out.println(rank+" approves loan of "+loan.getAmount());
      return true;
    }

    return false;
  }
}

经理

class Manager extends Employee{
  public Manager(){
    super("Manager", 5000);
  }
}

贷款

class Loan{
  private int amount;
  public Loan(int amount){
    this.amount = amount;
  }
  public int getAmount(){ return amount; }
}

主要

ILoanHandler man = new LoanHandler(new Manager());

嗯,虽然我觉得直觉是对的,但我有几点:

  • COR 模式没有具体说明如何在实际代码中实现它,因为有很多方法可以做到这一点(直接在具体的class, inheritance, generics, containment, composition etc),我认为这个模式试图描述一个想法的本质,忽略了细节。

  • 使用 wikipedia article 的术语:该模式最重要的方面是 Handler 接口。给定一个稳定且定义良好的接口,您可以实现您的 Receiver class 有多种选择,该选择取决于 其他考虑因素 。您提到了一个这样的考虑因素,即可重用性,因此您可以遵循单一责任原则(SRP):因为在您的特定情况下, Employee class 暗示了一个class 应该管理员工详细信息,那么贷款审批责任可能应该完全委托给 LoanApproval class,这样 Employee 就没有直接依赖于 LoanApproval(因此不实现 ILoanApprover)。为此,您可以遵循 清洁架构 原则,其中用例(例如 LoanApproval)应依赖于实体(例如 EmployeeLoan ) 而不是相反(事实上,更准确地说,依赖于实体的 segregated 接口,这是一个单独的问题)。另一种表达方式是说 Employee 可能不应该充当 RecieverSender。鉴于此,您可能(现在可能不会!)希望在 COR 模式之外使用 LoanApproval,这是再次分离的一个很好的论据,既可重用又可删除重复逻辑。您可以使用上面提到的一些方法来做到这一点,例如继承、泛型等...

  • 考虑上述问题的另一种相关方式是考虑当您需要为 Employee 添加其他 tasks/use-cases 时您的设计会发生什么。 Employee 将需要实现更多 Handler 接口,其中一些可能有冲突的函数名称等,这就是你陷入困境的地方,结果是你有一个核心 class随着越来越多的责任不断扩展。

因此,您考虑解耦责任、可重用性和删除重复代码绝对是正确的,并且有不同的方法可以做到这一点,但我认为这些问题与 COR 模式正交,即纯粹是关于能够在运行时动态地将任务链接在一起的优势。

P.S。在现实世界中,我已经看到这种模式以各种可怕的方式实施......有时以现实世界为指导并没有帮助!