The first issue involves the parent Task object. Since the graph of a parent cannot contain cycles, assigning Task A as a parent of Task B is not allowed when B is an ancestor of A. Task creation provides two separate constructors. One is for task creation and the other is provided to ensure that a task is not an ancestor of another.
Another consideration involves prerequisite tasks, which also cannot contain cycles. Assigning Task A as a prerequisite of Task B is not allowed when B is a prerequisite task of A. Also, a task cannot be a prerequisite of itself. To prevent cycles in prerequisites, a method is provided to determine whether a task is a prerequisite of another.
A third concern involves duration getting and setting. These are accomplished by accessing the instance variable for simple tasks. Simple tasks have no subtasks or prerequisites. Setting the duration time for a complex task is not allowed since it must be calculated from the duration times of the subtasks and prerequisite tasks. The method isSimple is provided to ensure data integrity by allowing the duration variable to be set only when the task is a simple task.
Another consideration ensures that the user does not have direct access to the data. Data members are made private and getting and setting methods for accessing them are provided. This illustrates the importance of the concept of encapsulation.
When a subtask is added, it is necessary to ensure that the task was not already there.
Tasks must have unique names. If this constraint is not satisfied, cycling could result.