9

Consider you got several validations. Those validations should only take effect if the object to be inspected is of a certain type. Why would I use a chain of responsibility over a switch-statement?

Example with chain of responsibility

public class Executor {

@Inject
private ValidatorFactory validatorFactory;

public void execute(Konfiguration konfig) {
    List<Statement> statements = konfig.getStatements();
    AbstractValidator validator = validatorFactory.create();
    for (Statement statement : statements) {
        if (validator.validate(statement.getType())) {
            crudService.execute(statement.getSql());
        }
    }
}

The validatorFactory creates the chain of Validators. One validator would look like

public class AddPrimaryKeyValidator extends AbstractValidator {

@Override
public boolean validate(Statement statement) {
    if (SqlType.ADD_PK.getTyp().equals(statement.getType())) {
        return doesTableAndPrimaryKeyExist(statement.getTabName());
    }
    return successor.validate(statement);
}

Example with switch-statement

public void execute(Konfiguration konfig) {
    List<Statement> statements = konfig.getStatements();
    for (Statement statement : statements) {
        switch (statement.getType()) {
        case "ADD_PK":
            if (doesTableAndPrimaryKeyExist(statement.getTabName())) {
                frepCrudService.execute(statement.getSql());
            }
            // more cases
        }
    }
}
Chris311
  • 3,794
  • 9
  • 46
  • 80

2 Answers2

8

Because in a chain of responsibility you don't need to know who does what up front in the caller. The logic of decide when you are about to run your piece of code in a chain is owned by you and the rest of the code can ignore it. This allow to encapsulate specific logic in the right place. Servlet filters are a good example of this

Filippo Fratoni
  • 379
  • 2
  • 7
0

Looks like an odd reason to use a chain of responsability. You are basically building a chain only to create a dynamic list of if statements, which is probably not dynamic anyway since I'm sure you hard-coded the chain initialization with one validator per statement.

I believe that chain of responsability is not the right pattern for this. You should replace if statements by polymorphism instead.

For instance if you have specialized Statement classes you can just do statement.validate(). Statement doesn't have to validate itself if you don't want to, it can just know which validator to use internally and delegate the validation to it.

If you do not have specialized statement classes you could ask the factory for the proper validator right away instead of building the entire chain.

plalx
  • 42,889
  • 6
  • 74
  • 90
  • You mean something like AbstractValidator validator = validatorFactory.create(statement.getType());? The factory itself works with switch-case then, in order to decide which validator to construct? – Chris311 Oct 20 '15 at 14:29
  • @Chris311 Yes, that's an option. But probably that having specialized `Statement` classes would be preferred (unless they only differ by their type). You may also work with a `StatementValidationService` instead of asking directly for a validator. This way the client can just `validationService.validate(statement)` and internally the validationService knows wich strategy to use. You may use a `Map` internally to bind types to strategies if you want to add new types dynamically. – plalx Oct 20 '15 at 14:41
  • I don't want different statement classes because it is mapped to an entity. I found another pretty nice solution: The Factory injects a validator interface with @Any. The validators know when they are applicable and then return themselves. – Chris311 Oct 20 '15 at 14:43
  • @Chris311 "I don't want different statement classes because it is mapped to an entity " How is that an issue? Persistence should not drive your design. – plalx Oct 20 '15 at 14:45
  • I still prefer the way with the @Any-Injection. I won't need a switch-statement then. – Chris311 Oct 21 '15 at 06:47
  • @Chris311 You wouldn't need a switch statement with specialized classes either. I don't get why you can't have them? Anyway, you may not have a switch statement (using a simple Map you wouldn't either by the way), but how do you configure the factory to inject the right validator? – plalx Oct 21 '15 at 12:33
  • With my solution I don't need a factory anymore. I am working with @Any @ Inject private Instance validator; Each validator has a isApplicable-method. Then I find the correct one by iterating over a foreach-loop. The solution looks really good. – Chris311 Oct 21 '15 at 13:48