1
\$\begingroup\$

I need to connect different Task with a double linked list and different Dependencies which affect a calculation for which I need the values of both Task:

public class Task {
    private List<Dependency> parents = new ArrayList<Dependency>();
    private List<Dependency> children = new ArrayList<Dependency>();

    //Uses the parents values and calls `calculateForwards` of the children
    public void calculateForwards() { .. }
    //Uses the children values and calls `calculateBackwards` of the children
    public void calculateBackwards() { .. }
}

public interface Dependency {
    Task getTask();
    void setForwards(Task t);
    void setBackwards(Task t);
    Dependency createCopy(Task t);
}


public class EA implements Dependency {
    private Task task;

    //............

    @Override
    public void setForwards(Task t) {
        if (t.getEarlyStart() < task.getEarlyFinish())
        t.setEarlyStart(task.getEarlyFinish());

        t.setEarlyFinish(t.getEarlyStart() + t.getDuration());
    }

    @Override
    public void setBackwards(Task t) {
        if (t.getLatestFinish() > task.getLatestStart())
        t.setLatestFinish(task.getLatestStart());

        t.setLatestStart(t.getLatestFinish() - t.getDuration());
    }

    //............

 }

For now dependencies are created with the Task it points to and added to the children list. Then a copy of the dependency is created that points to the original task and added to the parent list of the child:

public void addChild(Dependency r) {
    children.add(r);
    r.getTask().addParent(r.createCopy(this));
}

private void addParent(Dependency r) {
    parents.add(r);
}

As you can see this data structure does the job, but very ugly in my eyes. How can I solve this more elegantly?

\$\endgroup\$
1
\$\begingroup\$

Task depends on Dependency (not very troubling in itself) :

public class Task {
    private List<Dependency> parents = new ArrayList<Dependency>();

Also Dependency depends on concrete class Task (somewhat more troubling):

public interface Dependency {
    Task getTask();

Although dependency cycles of size 2 are not intrinsically a problem, in this case interface Dependency is pretty much useless, [if we look at the implementation, which is a hybrid holder and wrapper for Task]. Too generic a name and getters and setters on the interface are also signs that this interface does not pull its weight.

If the problem model is a graph it is expected that class that represents the node of that graph should be depend on itself. Dependency cycles of 1 is generally better than 2.

My Suggestion

The only methods that contain logic in the implementation of Dependency is setBackwards and setForwards. But when we read them we see that they manipulate the insides of Task, and therefore should be moved into that class. After the said move you can remove Dependency and EA, and directly use Task instead.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ So I need to move the graph stuff into Dependency? \$\endgroup\$ – Sven Mar 11 '13 at 9:53
  • \$\begingroup\$ @Sven I appended my suggestion to the answer. I suggest you should get rid of Dependency and EA. As for moving graph stuff elsewhere, it seems reasonable. I imagine a TaskNode class, which has a Task, having links to other TaskNodes makes sense. \$\endgroup\$ – abuzittin gillifirca Mar 11 '13 at 10:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.