0

How to build a chain of responsibility using constructor for initializing chains. Here is my Runner.class where i'm building my chain using setNext method.

public class Runner {

private static final String ENTER_PATH = "Enter path: ";
private static final String FILTER_BY_NAME = "Filter by name? (0/1)";
private static final String ENTER_NAME_PARAMETER = "Enter name parameter please: ";
private static final String FILTER_BY_EXTENSION = "Filter by extension? (0/1)";
private static final String ENTER_EXTENSION_PARAMETER = "Enter extension please (without '.'): ";
private static final String FILTER_BY_SIZE = "Filter by size? (0/1)";
private static final String ENTER_SIZE_TO = "Enter upper limit searching files in kb";
private static final String ENTER_SIZE_FROM = "Enter lower limit searching files in kb";
private static final String TRUE="1";
private Scanner scanner;

private List<File> fileList;


public Runner() {
    this.scanner = new Scanner(System.in);
    this.fileList = new ArrayList<>();
}

private String getDirName(){
    System.out.println(ENTER_PATH);
    return scanner.nextLine();
}


private Handler getChainOfResponsibility(){
    GeneralHandler generalHandler = new GeneralHandler();
    Handler lastHandler = generalHandler;


    System.out.println(FILTER_BY_NAME);
    if (scanner.nextLine().equals(TRUE)) {
        System.out.println(ENTER_NAME_PARAMETER);
        String name = scanner.nextLine();
        Handler nameHandler = new NameHandler(name);
        lastHandler.setHandler(nameHandler);
        lastHandler = nameHandler;
    }

    System.out.println(FILTER_BY_EXTENSION);
    if (scanner.nextLine().equals(TRUE)) {
        System.out.println(ENTER_EXTENSION_PARAMETER);
        Handler extensionHandler = new ExtensionHandler(scanner.nextLine());
        lastHandler.setHandler(extensionHandler);
        lastHandler = extensionHandler;
    }


    System.out.println(FILTER_BY_SIZE);
    if (scanner.nextLine().equals(TRUE)) {
        System.out.println(ENTER_SIZE_FROM);
        double fromSize = scanner.nextDouble();
        System.out.println(ENTER_SIZE_TO);
        double toSize = scanner.nextDouble();
        Handler sizeHandler = new SizeHandler(fromSize, toSize);
        lastHandler.setHandler(sizeHandler);
    }
    return generalHandler;
}


public void run() throws InterruptedException, IOException {
    findAllFiles(getDirName(), getChainOfResponsibility());
    showListOfFilteredFiles();

}

Here is my Handler abstract class

    public abstract class Handler {

    private Handler handler;

    public void setHandler(Handler handler) {
        this.handler = handler;
    }

    protected abstract boolean handleFilter(File file);

    public boolean doFilter(File file){
        if(handleFilter(file)){
            if(Objects.nonNull(handler)){
                return handler.doFilter(file);
            }
            return true;
        }
        return false;
    }

}

And also i have it's implementation. How to make, that it will be init through constructor! Help pls!

Serg Shapoval
  • 707
  • 1
  • 11
  • 39

1 Answers1

1

Preamble

Your implementation is wrong; the general way of implementing the Chain of Responsibility pattern is for each link in the chain to forward the request to the next link if it cannot handle the request itself. This is traditionally done by delegating to the abstract super class if the current class cannot handle the request. So in short, to comply with tradition, I would rewrite your Handler class as follows:

public abstract class Handler {
  private Handler next;

  public void setHandler(Handler next) {
    this.next = next;
  }

  public boolean doFilter(File file) {
    return next.doFilter(file);
  }
}

I have not read the contract of either your Handler nor NameHandler classes, but I'll just make a few assumptions in order to provide an example of how the NameHandler might look like after refactoring its parent:

public class NameHandler extends Handler {
  private final String name;

  public NameHandler(String name){
    this.name = name;
  }

  @Override
  public boolean doFilter(File file){
    final boolean result;

    if(file.getName().equals(name)){
      result = true;
    }else{
      result = super.doFilter(file);
    }

    return result;
  }
}

Answer

Use constructors to configure the next link in the chain as opposed to "setters" like your setHandler method:

public abstract class Handler {
  private final Handler next;

  public Handler(Handler next){
    this.next = next;
  }

  public boolean doFilter(File file){
    return next.doFilter(file);
  }
}

Now your subclasses are required to deal with the non-default constructor:

public class NameHandler extends Handler {
  private final String name;

  public NameHandler(String name, Handler next){
    super(next);
    this.name = name;
  }

  @Override
  public boolean doFilter(File file){
    final boolean result;

    if(file.getName().equals(name)){
      result = true;
    }else{
      result = super.doFilter(file);
    }

    return result;
  }
}
George Aristy
  • 1,373
  • 15
  • 17