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?
1 Answer 1
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.
-
\$\begingroup\$ So I need to move the graph stuff into Dependency? \$\endgroup\$Sven– Sven2013年03月11日 09:53:31 +00:00Commented Mar 11, 2013 at 9:53
-
\$\begingroup\$ @Sven I appended my suggestion to the answer. I suggest you should get rid of
Dependency
andEA
. As for moving graph stuff elsewhere, it seems reasonable. I imagine aTaskNode
class, which has aTask
, having links to otherTaskNode
s makes sense. \$\endgroup\$abuzittin gillifirca– abuzittin gillifirca2013年03月11日 10:50:52 +00:00Commented Mar 11, 2013 at 10:50