Search code examples
javadesign-patternsstrategy-patterntaskservice

Strategy Pattern with different parameters


I came across a problem when using the strategy pattern. I am implementing a service for creating tasks. This service also resolves the responsible clerk for this task. Resolving the clerk is done by using the strategy pattern because there are different ways of doing this. The point is that every strategy could need different parameters to resolve the clerk.

For example:

interface ClerkResolver {
    String resolveClerk(String department);
}

class DefaultClerkResolver implements ClerkResolver {

    public String resolveClerk(String department) {
        // some stuff
    }
}

class CountryClerkResolver implements ClerkResolver {

    public String resolveClerk(String department) {
        // I do not need the department name here. What I need is the country.
    }

}

The problem is that every resolver may depend on different parameters to resolve the responsible clerk. For me this sounds like a design issue in my code. I also tried to have a class as a parameter to keep all values that could be needed by the strategies, like:

class StrategyParameter {

   private String department;
   private String country;

   public String getDepartment() ...
}

interface ClerkResolver {
    String resolveClerk(StrategyParameter strategyParameter);
}

But to be honest, I am not satisfied with this solution because I have to change the parameter class everytime a strategy needs a new / different argument. And secondly the caller of the strategy must set all parameters because he does not know which strategy will resolve the clerk, therefore he has to provide all parameters (but this isn't that bad).

Again, for me this sounds like a design issue in my code, but I can't find a better solution.

--- EDIT

The main problem with this solution is when creating the task. The task service looks like this:

class TaskService {

    private List<ClerkResolver> clerkResolvers;

    Task createTask(StrategyParamter ...) {

        // some stuff

       for(ClerkResolver clerkResolver : clerkResolvers) {
          String clerk = clerkResolver.resolveClerk(StrategyParameter...)
          ...
       }

       // some other stuff
    }

}

As you can see when the TaskService is used, the caller must provide the necessary information to resolve the clerk, i.e. the department name and/or the country, because the TaskService itself doesn't have these information.

When a task has to be created, the caller must provide the StrategyParameter, because they are necessary to resolve the clerk. Again, the problem is, that the caller doesn't have all the information, i.e. he has no knowledge of the country. He can only set the department name. That's why I added a second method to the interface to ensure that the strategy can handle the clerk resolution:

interface ClerkResolver {
    String resolveClerk(StrategyParameter strategyParameter);
    boolean canHandle(StrategyParameter strategyParameter);
}

At the risk of repeating me, this solution doesn't sound right to me.

So, if anybody has a better solution for this problem I would appreciate to hear it.

Thanks for your comments!


Solution

  • I think there is some confusion about what the task actually is. In my thinking a task is something that is done by a clerk. So you are able to create a task itself without knowing about a clerk.

    Based on that task you can choose an appropriate clerk for it. The assignment of the task to the clerk can itself be wrapped to some other kind of task. So a common interface for choosing a clerk would be:

    interface ClerkResolver {
        String resolveClerk(Task task);
    }
    

    For implementing this kind of clerk resolver you can use the strategy pattern based on the actual type of the task for example.