Я читал о DDD уже несколько дней и мне нужна помощь в разработке этого образца. Все правила DDD меня очень смущают из-за того, как я вообще должен что-либо строить, когда объектам домена не разрешено показывать методы на уровне приложения; где еще организовать поведение? Хранилища не могут быть внедрены в сущности, и поэтому сами сущности должны работать на состояние. Тогда объект должен знать что-то еще из домена, но другие объекты объекта также не могут быть внедрены? Некоторые из этих вещей имеют смысл для меня, но некоторые нет. Я еще не нашел хороших примеров того, как создать целую функцию, так как каждый пример касается заказов и продуктов, повторяя другие примеры снова и снова. Я учусь лучше всего, читая примеры, и постарался создать функцию, используя информацию, которую я получил о DDD.
Мне нужна ваша помощь, чтобы указать, что я делаю неправильно и как это исправить, наиболее предпочтительно с помощью кода, так как «я бы не рекомендовал делать X и Y» очень трудно понять в контексте, где все уже смутно определено. Если я не могу внедрить сущность в другую, было бы легче понять, как это сделать правильно.
В моем примере есть пользователи и модераторы. Модератор может запретить пользователям, но с бизнес-правилом: только 3 в день. Я попытался настроить диаграмму классов, чтобы показать отношения (код ниже):
interface iUser
{
public function getUserId();
public function getUsername();
}
class User implements iUser
{
protected $_id;
protected $_username;
public function __construct(UserId $user_id, Username $username)
{
$this->_id = $user_id;
$this->_username = $username;
}
public function getUserId()
{
return $this->_id;
}
public function getUsername()
{
return $this->_username;
}
}
class Moderator extends User
{
protected $_ban_count;
protected $_last_ban_date;
public function __construct(UserBanCount $ban_count, SimpleDate $last_ban_date)
{
$this->_ban_count = $ban_count;
$this->_last_ban_date = $last_ban_date;
}
public function banUser(iUser &$user, iBannedUser &$banned_user)
{
if (! $this->_isAllowedToBan()) {
throw new DomainException('You are not allowed to ban more users today.');
}
if (date('d.m.Y') != $this->_last_ban_date->getValue()) {
$this->_ban_count = 0;
}
$this->_ban_count++;
$date_banned = date('d.m.Y');
$expiration_date = date('d.m.Y', strtotime('+1 week'));
$banned_user->add($user->getUserId(), new SimpleDate($date_banned), new SimpleDate($expiration_date));
}
protected function _isAllowedToBan()
{
if ($this->_ban_count >= 3 AND date('d.m.Y') == $this->_last_ban_date->getValue()) {
return false;
}
return true;
}
}
interface iBannedUser
{
public function add(UserId $user_id, SimpleDate $date_banned, SimpleDate $expiration_date);
public function remove();
}
class BannedUser implements iBannedUser
{
protected $_user_id;
protected $_date_banned;
protected $_expiration_date;
public function __construct(UserId $user_id, SimpleDate $date_banned, SimpleDate $expiration_date)
{
$this->_user_id = $user_id;
$this->_date_banned = $date_banned;
$this->_expiration_date = $expiration_date;
}
public function add(UserId $user_id, SimpleDate $date_banned, SimpleDate $expiration_date)
{
$this->_user_id = $user_id;
$this->_date_banned = $date_banned;
$this->_expiration_date = $expiration_date;
}
public function remove()
{
$this->_user_id = '';
$this->_date_banned = '';
$this->_expiration_date = '';
}
}
// Gathers objects
$user_repo = new UserRepository();
$evil_user = $user_repo->findById(123);
$moderator_repo = new ModeratorRepository();
$moderator = $moderator_repo->findById(1337);
$banned_user_factory = new BannedUserFactory();
$banned_user = $banned_user_factory->build();
// Performs ban
$moderator->banUser($evil_user, $banned_user);
// Saves objects to database
$user_repo->store($evil_user);
$moderator_repo->store($moderator);
$banned_user_repo = new BannedUserRepository();
$banned_user_repo->store($banned_user);
Должно ли право пользователя иметь 'is_banned'
поле, которое можно проверить $user->isBanned();
? Как снять бан? Я понятия не имею.