Czytałem o DDD od kilku dni i potrzebuję pomocy w tym przykładowym projekcie. Wszystkie reguły DDD powodują, że jestem bardzo zdezorientowany tym, jak mam cokolwiek zbudować, gdy obiekty domeny nie mogą pokazywać metod w warstwie aplikacji; gdzie jeszcze koordynować zachowanie? Repozytoria nie mogą być wstrzykiwane do podmiotów, a same podmioty muszą zatem działać na stan. Zatem encja musi wiedzieć coś jeszcze z domeny, ale inne obiekty encji też nie mogą być wstrzykiwane? Niektóre z tych rzeczy mają dla mnie sens, ale niektóre nie. Muszę znaleźć dobre przykłady, jak zbudować całą funkcję, ponieważ każdy przykład dotyczy zamówień i produktów, powtarzając inne przykłady w kółko. Uczę się najlepiej, czytając przykłady i próbowałem zbudować funkcję, korzystając z informacji uzyskanych do tej pory o DDD.
Potrzebuję twojej pomocy, aby wskazać, co robię źle i jak to naprawić, najlepiej za pomocą kodu, ponieważ „nie polecam robienia X i Y” jest bardzo trudne do zrozumienia w kontekście, w którym wszystko jest już niejasno zdefiniowane. Jeśli nie mogę wstrzyknąć bytu innemu, łatwiej byłoby zobaczyć, jak to zrobić poprawnie.
W moim przykładzie są użytkownicy i moderatorzy. Moderator może banować użytkowników, ale z regułą biznesową: tylko 3 dziennie. Podjąłem próbę skonfigurowania diagramu klas, aby pokazać relacje (kod poniżej):
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);
Czy uprawnienie użytkownika powinno zawierać 'is_banned'
pole, które można sprawdzić $user->isBanned();
? Jak usunąć ban? Nie mam pojęcia.