5
\$\begingroup\$

I have a lot of Command objects. Each command has lots of Task objects. Tasks and commands are related. Each command wants to know which task belongs to it. Where each task wants to know which command it belongs to.

class Command:

    def __init__(self, date):
        self.deadline = date
        self.tasks = []

    def add_task(self, task:Task):
        """
        add a task to this command
        """
        self.tasks.append(task)
        return task

    def has_task(self, task):
        return task in self.tasks

    def remove_task(self, task):
        """
        Remove the task from this command.  After calling this, 
        the task is orphaned and the reference to the task should be discarded.
        """
        self.tasks.remove(task)


class Task:
    def __init__(self, command:Command, duration:int):
        self.duration = duration
        self._command = command

    @property
    def command(self):
        """
        Getter for self._command with sanity checking that 
        the task is not orphaned.
        """
        if not self._command.has_task(self):
            raise ValueError("orphaned task")
        return self._command

class Problem:
    def __init__(self, commands:Dict[str,Command], tasks:Dict[str,Task]):
        self._commands = commands
        self._tasks = tasks

In the Problem object I feel there is some redundancy in the data between Commands and Tasks.

I fix starting times in two ways:

  1. Fix the start time of tasks command by command.
    This is why is a commands attribute in Problem.
  2. Merge them and then fix the starting times.
    This is why there is tasks attribute in Problem.

I need both ways to fix starting times. However, fixing the starting time of a task always depends on the deadline of the command to which it belongs.

I'm unsure if my design is good. Sometimes I need to go through the tasks command by command. Sometimes I need to consider all the tasks for the command they belong.
Is there a design pattern I can use?

\$\endgroup\$
  • \$\begingroup\$ @Peilonrayz I fixed it \$\endgroup\$ – user228433 Jul 29 at 23:43
  • \$\begingroup\$ Thank you :D looks good \$\endgroup\$ – Peilonrayz Jul 29 at 23:44
1
\$\begingroup\$

Maintaining bidirectional relationships

Rather than this check:

    if not self._command.has_task(self):
        raise ValueError("orphaned task")

it would be better to mark the task as orphaned by nulling out its command. In other words,

def remove_task(self, task):
    """
    Remove the task from this command.  After calling this, 
    the task is orphaned and the reference to the task should be discarded.
    """
    task.command = None
    self.tasks.remove(task)

Having command as a simple, "public", possibly-None member on Task is simpler. At most, I would give this a type hint of Optional[Command] in the constructor.

Types

Don't call date date; that's a commonly used class in a built-in library.

deadline should probably be of type datetime (not date), and duration should be of type timedelta, not int.

| improve this answer | |
\$\endgroup\$

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.