Cześć,
wyobraźmy sobie program typu issue tracker. Mam encję (w rozumieniu DDD):
class Issue:
id: UUID
name: str
description: str
author_id: UUID
status: IssueStatus
assignee_id: Optional[UUID]
class IssueStatus(Enum):
TODO = 1
IN_PROGRESS = 2
DONE = 3
**Pytanie 1** W encji chciałbym mieć metody `Issue.start()` i `Issue.finish()`, które zmieniałyby status odpowiednio z `TODO` na `IN_PROGRESS` i z `IN_PROGRESS` na `DONE`. Nie chcę pozwolić na jakiekolwiek inne zmiany statusu, np. nie można z `DONE` wrócić na `IN_PROGRESS` wywołując metodę `Issue.start()` ponownie. Jak do tego podejść? Wymyśliłem dwa rozwiązania: a) Rzucić odpowiedni wyjątek w metodach, np: ```python class Issue: [...] def start(self): if self.status != IssueStatus.TODO: raise InvalidIssueStatus() self.status = IssueStatus.IN_PROGRESS ```` b) Wyrzucić status z encji i użyć dziedziczenia: ```python class Issue: id: UUID name: str description: str author_id: UUID assignee_id: Optional[UUID]
class TodoIssue(Issue):
def start(self):
return StartedIssue(...)
class StartedIssue(Issue):
def finish(self):
return FinishedIssue(...)
class FinishedIssue(Issue):
pass
Które lepsze? A może warto do tego podejść jeszcze inaczej?
<hr />
**Pytanie 2**
`Issue.assignee_id` jest opcjonalnie. Załóżmy, że nie można wystartować issue, które nie jest do nikogo przypisane, ergo każde issue o statusie `IN_PROGRESS` i `DONE` ma przypisanego pracownika. Jak taki kontrakt zawrzeć w kodzie? Walidacja w konstruktorze encji? Znowu dziedziczenie (np. abstrakcyjne `Issue` i dzieci `UnassignedIssue` i `AssignedIssue`)?