DDD, объект состояния / объекты значения

У меня есть класс, Proposal, который имеет статус $ ProposalStatus. Теперь, по большей части, идентичность ProposalStatus не меняется … но она (вроде). $ Id является фиксированным, но $ display_name и $ definition (только строки) могут меняться в течение длительного периода времени при обновлении основных данных, но он НЕ изменится в течение срока действия HTTP-запроса-ответа.

Вопрос 1 — Сущность или объект значения?

Является ли объект ценности чем-то никогда должен измениться или только никогда не должен меняться в течение срока действия конкретного выполнения приложения? Если отображаемое имя или определение будут изменены, то я действительно ожидаю / хочу, чтобы оно было изменено для всех. Тем не менее, так как они может быть определено вне предложения Я думаю, что просто прямо делает их сущностями, а не объектами стоимости.

Предложение никогда не изменяет атрибуты ProposalStatus, оно только меняет то, что имеет ProposalStatus.

Вопрос 2 — Как правильно установить статус для доменного дизайна?

У моего объекта предложения есть возможность управлять его статусами, но для этого мне нужен определенный объект ProposalStatus. Только, где находится список статусов, который позволяет ему вернуть ожидаемое право?

  • Я мог бы получить его из ProposalRepository … но все доступно через совокупный корень, который Proposal, так что это не имеет смысла.
  • Я мог бы иметь константы, которые соответствуют $ id ProposalStatus, но это кажется неправильным.
  • Я мог бы создать ProposalStatusRepository … но должен ли я получить доступ к другому хранилищу изнутри Proposal?
  • Я мог бы создать массив всех возможных состояний с $ id в качестве ключа и добавить в предложение, но это не сильно отличается от хранилища …

Пример:

class ProposalStatus {
protected $id; // E.g., pending_customer_approval
protected $display_name; // E.g., Pending Customer Approval
protected $definition; // E.g., The proposal needs to be approved by the customer
}

class Proposal {
/**
* The current status of the proposal
* @var ProposalStatus
*/
protected $proposal_status;

public function withdraw() {
// verify status is not closed or canceled
// change status to draft
}

public function submit() {
// verify status is draft
// change status to pending customer approval
}

public function approve() {
// verify status is pending customer approval
// change status to approved
}

public function reject() {
// verify status is pending customer approval
// change status to rejected
}

public function close() {
// verify status is not canceled
// change status to closed
}

public function cancel() {
// verify status is not closed
// change status to canceled
}
}

0

Решение

Является ли список всех возможных статусов предложения статичным? Я думаю, что это. Таким образом, ProposalStatus выглядит как простое перечисление. Такие атрибуты, как DisplayName и Definition, не связаны с бизнес-кодом.

Просто определите ProposalStatus как перечисление (статический класс с полями только для чтения или любой другой структурой, поддерживаемой вашим языком). Это должно быть определено на бизнес-уровне. Код бизнес должен уметь различать значения перечисления (например, if (offer.Status == ProposalStatus.Pending) {poposal.Status = ProposalStatus.Approved;}).

В приложении или даже на уровне представления определите словарь, содержащий DisplayName и Definition, сопоставленные с ProposalStatus. Он будет использоваться только при отображении данных пользователям.

0

Другие решения

Из того, что я понимаю из вашего домена, ProposalStatus должен быть Value object, Таким образом, он должен быть неизменным и содержать определенное поведение. В вашем случае поведение тестирует определенное значение и инициализирует только допустимый диапазон значений. Вы можете использовать класс PHP с закрытым конструктором и статическими методами фабрики.

/**
* ProposalStatus is a Value Object
*/
class ProposalStatus
{
private const DRAFT                     = 1;
private const PENDING_CUSTOMER_APPROVAL = 2;
private const CANCELLED                 = 3;
private const CLOSED                    = 4;

/** @var int */
private $primitiveStatus;

private function __construct(int $primitiveStatus)
{
$this->primitiveStatus = $primitiveStatus;
}

private function equals(self $another): bool
{
return $this->primitiveStatus === $another->primitiveStatus;
}

public static function draft(): self
{
return new static(self::DRAFT);
}

public function isDraft(): bool
{
return $this->equals(static::draft());
}

public static function pendingCustomerApproval(): self
{
return new static(self::PENDING_CUSTOMER_APPROVAL);
}

public function isPendingCustomerApproval(): bool
{
return $this->equals(static::pendingCustomerApproval());
}

public static function cancelled(): self
{
return new static(static::CANCELLED);
}

public function isCancelled(): bool
{
return $this->equals(static::cancelled());
}

public static function closed(): self
{
return new static(static::CLOSED);
}

public function isClosed(): bool
{
return $this->equals(static::closed());
}
}

class Proposal
{
/** @var ProposalStatus */
private $status;

public function __construct()
{
$this->status = ProposalStatus::draft();
}

public function withdraw()
{
if (!$this->status->isClosed() && !$this->status->isCancelled()) {
$this->status = ProposalStatus::draft();
}
}

// and so on...
}

Обратите внимание, что неизменность является важной характеристикой объекта Value.

1

В случае, если ваш ProposalStatus это фиксированный список значений просто перейти на перечисление подход.

В противном случае вам нужно лечить ProposalStatus как AggregateRoot что пользователи могут создавать, обновлять и удалять (я думаю). При назначении ProposalStatus к Proposal вам просто нужно удостоверение личности. Если вы хотите проверить, что данный идентификатор существует, вам просто нужно удовлетворить инвариант с помощью специального запроса. Спецификация шаблон хорошо подходит здесь.

class ProposalStatusExistsSpecification
{
public function isSatisfiedBy(string $proposalSatusId): bool
{
//database query to see if the given ID exists
}
}

Ты можешь найти Вот Interfaces реализовать вашу спецификацию.

0
По вопросам рекламы [email protected]