Я читав про 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();
? Як зняти заборону? Я поняття не маю.