Кто отвечает за процесс с запросами API в доменном уровне DDD (Domain Driven Design) - PullRequest
0 голосов
/ 19 января 2019

Я новичок в DDD.

Понятия не имею, кто отвечает за процесс с запросом API.
Я понятия не имею, кто отвечает за функцию, косвенно зависящую от уровня инфраструктуры.
Например, функция с запросом веб-API.

Например, я создаю систему онлайн-покупок, и система поддерживает отмену заказа.

Я думаю, у меня есть 2 кандидата в классы на уровне домена для реализации функции отмены заказа. A: Доменная служба B: Доменный объект

Но я не могу судить, что лучше.

Я беспокоюсь, что дизайн «А» слишком процедурный и выглядит анемичным.
Я также беспокоюсь о том, что дизайн "B" делает предметный объект слишком осведомленным и зависимым. (Потому что я думаю, что объект должен быть максимально простым)

Кандидат в проектировщики A

// Simple but anemic
class Order {
    id: number;
    date: Date;
    state: OrderState;

    constructor(
        ...
    ) {
        ...
    }
}

// Procedural
class OrderService {
    private readonly orderRepository: OrderRepository;

    constructor(
        orderRepository: OrderRepository
    ) {
        ...
    }

    cancel(orderId: number): void {
        orderRepository.update(orderId, { state: OrderSate.Cancelled });
    }
}

Кандидат в проектировщики B

// knowledgeable and dependent
class Order {
    id: number;
    date: Date;
    state: OrderState;

    private readonly orderRepository: OrderRepository;

    constructor(
        orderRepository: OrderRepository,
        ...
    ) {
        ...
    }

    cancel(): void {
        orderRepository.update(this.id, { state: OrderSate.Cancelled });
    }
}

Модель, которую я думал

Ответы [ 2 ]

0 голосов
/ 19 января 2019

Я новичок в DDD. Я понятия не имею, кто отвечает за процесс с запросом API.

Бизнес-логика принадлежит модели предметной области, оркестровка принадлежит приложению.

Таким образом, логика в вашем приложении обычно будет выглядеть примерно так ...

Order order = orderRepository.get(orderId);
order.cancel();

Модель Порядка отвечает за знание того, как манипулировать собственной структурой данных в памяти, когда вызывается Order::cancel. OrderRepository отвечает за постоянство. Приложение запускает вызов двух других элементов.

Часть путаницы заключается в том, что понятие «сервис» перегружено. В DDD «служба домена» относится к шаблону, являющемуся частью модели домена (точно так же, как объекты значений и сущности являются шаблонами модели домена).

Обновление 20190120

Но кто обновляет базу данных на сервере? Ваш код кажется, что база данных на сервере еще не была обновлена, если order.cancel () обновляет только собственную память. Это мое мышление.

Это действительно важный вопрос, не так ли? :)

Когда Эрик Эванс впервые описал шаблон репозитория в своей книге, он сознательно выбрал шаблон репозитория с семантикой сбора и предложил, чтобы управление транзакциями было приложением .

В псевдокоде:

beginTransaction();
Order order = orderRepository.get(orderId);
order.cancel();
commitTransaction();

Суть в том, что базовый mapper может просмотреть хранилище и определить, какие объекты являются "грязными", и, таким образом, сгенерировать соответствующие вызовы для вашего постоянного хранилища.

В последнее время вы с большей вероятностью увидите репозитории с хранилищем , а не с семантикой

beginTransaction();
Order order = orderRepository.get(orderId);
order.cancel();
orderRepository.save(order);
commitTransaction();

Основная механика та же самая, но мы устранили некоторые из магии того, как изменения делятся.

0 голосов
/ 19 января 2019

Есть альтернативы этим опциям.Один из них - покончить с хранилищем, и пусть модель определит поведение:

public interface Order {
    void cancel();
}

, а затем реализует поведение с помощью определенной технологии:

public final class SqlOrder implements Order {
    ...
    @Override
    public void cancel() {
        connection.execute("update order...");
    }
}

В зависимостив ваших случаях использования это может привести к следующим преимуществам: не является анемичным, избавляется от потенциально ненужной косвенности (хранилища), использует язык домена, а не технические аспекты CRUD, более удобен в обслуживании, легко тестируется, потому что заказ теперь является просто интерфейсом и т. д..

...