Saya sudah membaca tentang DDD selama berhari-hari sekarang dan butuh bantuan dengan desain sampel ini. Semua aturan DDD membuat saya sangat bingung dengan bagaimana saya seharusnya membangun apa saja ketika objek domain tidak diperbolehkan menunjukkan metode ke lapisan aplikasi; di mana lagi untuk mengatur perilaku? Repositori tidak diizinkan untuk disuntikkan ke entitas dan entitas itu sendiri harus bekerja pada negara. Maka suatu entitas perlu mengetahui sesuatu yang lain dari domain, tetapi objek entitas lain juga tidak diizinkan untuk disuntikkan? Beberapa hal ini masuk akal bagi saya tetapi beberapa tidak. Saya belum menemukan contoh yang baik tentang bagaimana membangun seluruh fitur karena setiap contoh adalah tentang Pesanan dan Produk, mengulangi contoh-contoh lainnya berulang-ulang. Saya belajar paling baik dengan membaca contoh dan telah mencoba membangun fitur menggunakan informasi yang saya dapatkan tentang DDD sejauh ini.
Saya butuh bantuan Anda untuk menunjukkan apa yang saya lakukan salah dan bagaimana memperbaikinya, paling disukai dengan kode sebagai "Saya tidak akan merekomendasikan melakukan X dan Y" sangat sulit untuk dipahami dalam konteks di mana semuanya sudah didefinisikan secara samar-samar. Jika saya tidak bisa menyuntikkan entitas ke entitas lain, akan lebih mudah untuk melihat bagaimana melakukannya dengan benar.
Dalam contoh saya ada pengguna dan moderator. Seorang moderator dapat mencekal pengguna, tetapi dengan aturan bisnis: hanya 3 per hari. Saya melakukan upaya menyiapkan diagram kelas untuk menunjukkan hubungan (kode di bawah):
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);
Haruskah hak Pengguna memiliki 'is_banned'
bidang yang dapat diperiksa $user->isBanned();
? Bagaimana cara menghapus larangan? Saya tidak punya ide.
sumber
Jawaban:
Pertanyaan ini agak subyektif dan mengarah ke lebih banyak diskusi daripada jawaban langsung, yang, seperti yang ditunjukkan orang lain - tidak sesuai untuk format stackoverflow. Yang mengatakan, saya pikir Anda hanya perlu beberapa contoh kode tentang cara mengatasi masalah, jadi saya akan mencobanya, hanya untuk memberi Anda beberapa ide.
Hal pertama yang saya katakan adalah:
Itu tidak benar - saya akan tertarik untuk mengetahui dari mana Anda membaca ini. Lapisan aplikasi adalah orkestra antara UI, Infrastruktur & Domain, dan karenanya jelas perlu memanggil metode pada entitas domain.
Saya telah menulis contoh kode tentang bagaimana saya akan mengatasi masalah Anda. Saya minta maaf karena itu dalam C #, tapi saya tidak tahu PHP - mudah-mudahan Anda masih mendapatkan intisari dari perspektif struktur.
Mungkin seharusnya saya tidak melakukannya, tetapi saya telah sedikit memodifikasi objek domain Anda. Mau tidak mau saya merasa itu sedikit cacat, dalam konsep 'BannedUser' ada dalam sistem, bahkan jika larangan telah berakhir.
Untuk memulainya, inilah layanan aplikasi - inilah yang akan disebut UI:
Cukup lurus ke depan. Anda menjemput moderator yang melakukan pelarangan, pengguna yang ingin dilarutkan oleh moderator, dan memanggil metode 'Larangan' pada pengguna, melewati moderator. Ini akan mengubah status moderator & pengguna (dijelaskan di bawah), yang kemudian perlu bertahan melalui repositori terkait.
Kelas Pengguna:
Yang invarian bagi pengguna adalah mereka tidak dapat melakukan tindakan tertentu saat dicekal, jadi kami harus dapat mengidentifikasi apakah pengguna saat ini dicekal. Untuk mencapai hal ini, pengguna menyimpan daftar larangan penayangan yang telah dikeluarkan oleh moderator. Metode IsBanned () memeriksa semua larangan penayangan yang belum kedaluwarsa. Ketika metode Ban () dipanggil, ia menerima moderator sebagai parameter. Ini kemudian meminta moderator untuk mengeluarkan larangan:
Yang lain dari moderator adalah ia hanya dapat mengeluarkan 3 larangan per hari. Jadi, ketika metode IssueBan dipanggil, ia memeriksa bahwa moderator tidak memiliki 3 larangan yang dikeluarkan dengan tanggal hari ini dalam daftar larangan yang dikeluarkan. Kemudian menambahkan larangan yang baru dikeluarkan ke daftar itu dan mengembalikannya.
Subyektif, dan saya yakin seseorang akan tidak setuju dengan pendekatan itu, tetapi mudah-mudahan itu memberi Anda ide atau bagaimana itu bisa cocok bersama.
sumber
Pindahkan semua logika Anda yang mengubah status ke lapisan layanan (mis: ModeratorService) yang tahu tentang Entitas dan Repositori.
sumber