Domain services and Domain Entities

Обсуждаем, как правильно строить приложения
Ответить
sda
Сообщения: 334
Зарегистрирован: 2013.12.19, 09:29

Domain services and Domain Entities

Сообщение sda »

Скажите, правильно ли понимаю, что в доменных сервисах должна быть бизнес-логика, которая не относится ни к одному из доменных объектов? Ну типичные примеры, это когда бизнес-логика затрагивает несколько доменных объектов или какие-то вычисления, то это вот всё должно быть в доменных сервисах, верно?

Доменный объект должен содержать только состояние и методы, которые это состояние меняют и бизнес-правила (валидация), что такие-то свойства должны быть обязательны, должны иметь определенный тип данных и т.д. и кидать экзепшены если эти бизнес-правила нарушены. Доменный объект не должен содержать никаких методов, которые не изменяют его состояние верно?
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Domain services and Domain Entities

Сообщение ElisDN »

sda писал(а):Скажите, правильно ли понимаю, что в доменных сервисах должна быть бизнес-логика, которая не относится ни к одному из доменных объектов? Ну типичные примеры, это когда бизнес-логика затрагивает несколько доменных объектов или какие-то вычисления, то это вот всё должно быть в доменных сервисах, верно?
Правильно.
sda писал(а):Доменный объект должен содержать только состояние и методы, которые это состояние меняют и бизнес-правила (валидация), что такие-то свойства должны быть обязательны, должны иметь определенный тип данных и т.д. и кидать экзепшены если эти бизнес-правила нарушены. Доменный объект не должен содержать никаких методов, которые не изменяют его состояние верно?
Могут и считывающие это состояние геттеры быть вроде $user->getName() и $user->isActive().
sda
Сообщения: 334
Зарегистрирован: 2013.12.19, 09:29

Re: Domain services and Domain Entities

Сообщение sda »

Если доменный объект содержит массив других объектов, может ли в доменном объекте быть геттер который по некоторому аргументу находит и возвращает один из элементов этого массива?
sda
Сообщения: 334
Зарегистрирован: 2013.12.19, 09:29

Re: Domain services and Domain Entities

Сообщение sda »

ElisDN я могу в entity присваивать дефолтное значение свойству если значение для этого свойства не было передано в конструктор?
Аватара пользователя
SiZE
Сообщения: 2817
Зарегистрирован: 2011.09.21, 12:39
Откуда: Perm
Контактная информация:

Re: Domain services and Domain Entities

Сообщение SiZE »

sda писал(а):в доменных сервисах должна быть бизнес-логика
домен - это бизнес-логика приложения, если верить книгам.
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Domain services and Domain Entities

Сообщение ElisDN »

sda писал(а):Если доменный объект содержит массив других объектов, может ли в доменном объекте быть геттер который по некоторому аргументу находит и возвращает один из элементов этого массива?
Здесь вопросы "возвращает для чего?" и "возвращает кому?"
sda
Сообщения: 334
Зарегистрирован: 2013.12.19, 09:29

Re: Domain services and Domain Entities

Сообщение sda »

ElisDN внутри агрегата чтобы получить некоторый элемент массива и затем произвести с помощью него некоторые манипуляции в корне агрегата.

Просто меня смущает тот факт, что доменный эксперт не говорит, что-то типа "Если у игрока сейчас нет противника, то его нужно назначить". Он просто говорит, что игроки могут ходить друг на друга по каким-то определенным правилам. А у меня так и напрашивается какой-нибудь метод hasEnemy и assignEnemy в сущности Player которая является частью агрегата Game, хотя экперт об этом вообще не упоминал. Вот я и не знаю на сколько это правильно, подобные методы используются только внутри агрегата для реализации бизнес-правил. Наружу не торчат. Наружу торчат только методы агрегата типа "сделать ход", которые уже внутри себя используют всякие hasEnemy и прочие методы из других сущностей, которые являются частями агрегата.
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Domain services and Domain Entities

Сообщение ElisDN »

sda писал(а):ElisDN я могу в entity присваивать дефолтное значение свойству если значение для этого свойства не было передано в конструктор?
Присваивайте:

Код: Выделить всё

class Order
{
    function create($email, $date) {
        $this->email = $email;
        $this->date = $date;
        $this->status = Status::DRAFT;
    }.
} 
Только не делаю необязательных параметров в конструкторе вроде такого:

Код: Выделить всё

class Status
{
    const DRAFT = 'draft';
    const ACTIVE = 'active';

    function __construct(DateTime $date, $value = null) {
        if (!empty($value) && Assertion::choise($value, [...])) {
            $this->value = $value;
        } else {
            $this->value = self::DRAFT;
        } 
        $this->date = $date;
    }
} 
так как IDE не подсветит, если что-то упустишь.

Вместо этого предпочитаю всё ставить обязательным, а для различных вариаций значений по умолчанию использовать дополнительные статические конструкторы:

Код: Выделить всё

class Status
{
    const DRAFT = 'draft';
    const ACTIVE = 'active';

    function __construct(DateTime $date, $value) {
        Assertion::choise($value, [...]);
        $this->value = $value;
        $this->date = $date;
    }
    
    static function draft(DateTime $date) {
        return new self($date, self::DRAFT);
    }
    
    static function active(DateTime $date) {
        return new self($date, self::ACTIVE);
    }
    
    ...
} 
и запускать их при необходимости вместо new:

Код: Выделить всё

class Order implements AggregateRoot
{
    public function activate(DateTime $date, AvailabilityChecker $checker) {
        $this->guardIsDraft();
        $this->guardIsReadyToActivate($checker);
        $this->status = Status::active($date);
        $this->recordEvent(new OrderActivateEvent($this));
    }
    
    private function guardIsDraft() {
        if (!$this->status->isDraft()) {
             throw new \DomainException('Order is not a draft.');
        }
    }
    
    private function guardIsReadyToActivate(AvailabilityChecker $checker) {
        if (!$this->items->count())) {
             throw new \DomainException('Order has not items.');
        }
        if (!$checker->check($this->items->getAll())) {
             throw new \DomainException('Some items are not available to order.');
        }
        if (!$this->address->isCorrect()) {
             throw new \DomainException('Delivery address is not correct.');
        }
    }
} 
Последний раз редактировалось ElisDN 2016.10.25, 01:50, всего редактировалось 1 раз.
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Domain services and Domain Entities

Сообщение ElisDN »

sda писал(а):ElisDN внутри агрегата чтобы получить некоторый элемент массива и затем произвести с помощью него некоторые манипуляции в корне агрегата.
Внутри агрегату всё можно. Он там всему хозяин. Просто по вопросу
sda писал(а):Если доменный объект содержит массив других объектов, может ли в доменном объекте быть геттер...
непонятно было, кто здесь кто.
Последний раз редактировалось ElisDN 2016.10.25, 01:55, всего редактировалось 1 раз.
sda
Сообщения: 334
Зарегистрирован: 2013.12.19, 09:29

Re: Domain services and Domain Entities

Сообщение sda »

Ну есть агрегат Game, он содержит в себе массив сущностей Team, каждая сущность Team содержит в себе массив сущностей Player. Теперь Game хочет получить конкретного Player, чтобы использовать его для каких-то своих вычислений. Вот я и спрашиваю, может ли сущность Team содержать геттер Team::getPlayer($id), чтобы потом Game мог использовать этот метод внутри себя?
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Domain services and Domain Entities

Сообщение ElisDN »

sda писал(а):может ли сущность Team содержать геттер Team::getPlayer($id), чтобы потом Game мог использовать этот метод внутри себя?
Да, может.
sda
Сообщения: 334
Зарегистрирован: 2013.12.19, 09:29

Re: Domain services and Domain Entities

Сообщение sda »

Спасибо. По поводу дефолтных значений я то планировал делать это примерно так если на пхп

Код: Выделить всё

class Status
{
    const DRAFT = 'draft';
    const ACTIVE = 'active';

    function __construct(DateTime $date, $value = null) {
        $this->date = $date;
        $this->value = $value ?: self::DRAFT;
        
        Assertion::choise($this->value, [...]);
    }
}
Просто я не знаю нарушает ли это как-то концепцию ддд или нет?
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Domain services and Domain Entities

Сообщение ElisDN »

sda писал(а):Просто я не знаю нарушает ли это как-то концепцию ддд или нет?
DDD - это общая архитектурная идея про программирование осмысленным человеческим языком с полноценными объектами из ООП вроде

Код: Выделить всё

$отделКадров->наймиСотрудника(new Человек('Вася', 'Пупкин', new Паспорт('5432-1234567')), 'Дворник', 8000); 
а не низкоуровневой гиковской возне $a = 'Вася', mysql_query...

И всё. Пишете по человечески сервисами "отдел кадров" и сущностями "сотрудник" - значит всё нормально. Пишете непонятным лапшекодом $array, preg_match, fopen - до DDD как до Китая.

Это про уровень мышления. А Вы на примитивный уровень абстракции спускаетесь и к переменным привязываетесь.
Ответить