jeudi 11 janvier 2018

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

I have been focusing on learning programming principles and patterns but the chain of responsibility examples I have found all seem to contradict other principles/patterns. The placement of sethandler and nexthandler directly in a class that will do more than just that seems like a really really bad idea.

While trying to learn previously patterns I did find lots of unrealistically simple examples so at first I thought that to was the case with the examples I found. But after lots of googling I could not find any examples coming close to what I imagined it should be. So then I started checking articles and I could not find even a short sentence about how the handler functionality should be separate from the class that is using it.

It got me thinking maybe it is not such a big deal to have the chain of responsibility on a concrete class since its just two methods.

But again, that just seems really really wrong. If you want to use the class in a non chain of responsibility pattern way somewhere else what would you do since the Chain of Responsibility functionality is built directly into the class.

After going through pages and pages of google articles about the chain of responsibility and finding nothing about this topic I did eventually find one example which implements the functionality with a wrapper class. It pretty much delegates a concrete class into a wrapper class so that the concrete class could still be used without needing the chain of responsibility functionality.

So my question is.. will most real world implementations of the chain of responsibility principle use a wrapper class or will it be directly in the class? Maybe I just misunderstood the situations this pattern would actually be used in?

To really be able to compare and understand each method I decided to write my own examples using both methods. Below I pasted the most important parts of both and linked to the full examples.

Normal Method

ILoanApprover

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

Employee

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);
  }
}

Manager

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

Loan

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);
}

LoanHandler

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);
    }
  }
}

Employee

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;
  }
}

Manager

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

Loan

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

Main

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

Aucun commentaire:

Enregistrer un commentaire