lundi 4 mai 2015

get objects with a certain state using state pattern

I was assigned to design a piece of software (in java) with projects and jobs where jobs each have a status. As we learned about the GoF-patterns, the State pattern seemed like an obvious choice to me, but now I'm having some troubles with the implementation.

In my current design I have a Job-class to represent the job with a certain state and a Project-class that has a list of jobs. To represent the four possible states (AVAILABLE - UNAVAILABLE - FINISHED - FAILED), I made an enum State with the state dependent methods of job implemented in the enum.

The issues with the state-pattern I'm having are the following:

  1. In Project, I would like to have a method that returns all AVAILABLE jobs of the project (and maybe even one that returns all jobs that are either FINISHED or FAILED), but the state pattern doesn't mention on how to do this. We also got to hear that having methods as public boolean isAvailable() in Job or State should not be used when using the state pattern (because this is exactly what one wants to avoid when using this pattern).
  2. There is need for a method that changes the state from an AVAILABLE task to either FINISHED or FAILED. The problem with this is that I'm not really sure on how to implement this when using the State pattern.

I have some solutions in mind, but I would like to know whether there are other/better solutions to implement the state pattern well.

  1. For the first problem, I would implement a public Collection<Job> filter(Collection<Job>) method in State that would return the subset of the given set with only those jobs that are of the current state. The getAvailableJobs() method in Project would be like below. The disadvantage of this approach for me is that coupling grows when Project needs to know about State as well.
  2. For the second problem I could either write a update(State newState) method where I could check whether newState is either finished or failed or I could write a method fail() and a method finish() (both in State of course). The problem with the second seems to be the fact that some of the state logic gets back in the Task, but I'm not sure whether the update method is the best method either.

I hope I have been clear enough and that someone can help me understand why these solutions would be good enough or bad and what possible alternatives might be.

// in Project
public Collection<Job> getAvailableJobs() {
    return Status.AVAILABLE.filter(getTasks());
}

// in State
public Collection<Job> filter(Collection<Job> jobs) {
    Collection<Job> result = new HashSet<>();

    for(Job j : jobs)
        if(j.getStatus() == this)
            result.add(j);

    return result;

Thanks in advance.

Aucun commentaire:

Enregistrer un commentaire