এই ডিজাইনটিকে কীভাবে যথাযথ ডিডিডির নিকটবর্তী করা যায়?


12

আমি এখন কয়েকদিন ডিডিডি নিয়ে পড়েছি এবং এই নমুনা ডিজাইনের সাহায্য দরকার। ডিডিডি-র সমস্ত বিধিগুলি আমাকে খুব বিভ্রান্ত করে তোলে যে কখন যখন ডোমেন অবজেক্টগুলিকে অ্যাপ্লিকেশন স্তরটিতে পদ্ধতিগুলি প্রদর্শন করার অনুমতি দেওয়া হয় না তখন কীভাবে আমি কিছু তৈরি করার কথা; অর্কেস্ট্রেট আচরণ আর কোথায়? সঞ্চিত্রে সত্তা ও সত্তাগুলিতে সন্ধানের জন্য ভান্ডারগুলিকে অনুমতি দেওয়া হয় না সুতরাং তারা অবশ্যই রাজ্যে কাজ করবে work তারপরে কোনও সত্তাকে ডোমেন থেকে অন্য কিছু জানা দরকার, তবে অন্যান্য সত্তা অবজেক্টগুলিকেও ইঞ্জেকশন দেওয়ার অনুমতি দেওয়া হয় না? এর মধ্যে কিছু জিনিস আমার কাছে বোধগম্য হয় তবে কিছু তা বোঝে না। প্রতিটি উদাহরণ অর্ডার ও পণ্য সম্পর্কে যেমন পুরো বৈশিষ্ট্যটি কীভাবে তৈরি করা যায় তার আরও ভাল উদাহরণ আমি এখনও খুঁজে পাইনি এবং অন্যান্য উদাহরণগুলি বারবার বারবার বলছি। আমি উদাহরণগুলি পড়ে ভালভাবে শিখি এবং এই পর্যন্ত ডিডিডি সম্পর্কে আমি যে তথ্য অর্জন করেছি তা ব্যবহার করে একটি বৈশিষ্ট্য তৈরির চেষ্টা করেছি।

আমার ভুলটি কীভাবে করা যায় এবং কীভাবে এটি ঠিক করা যায় তা বোঝাতে আমার আপনার সহায়তা দরকার, সর্বাধিক কোড হিসাবে "আমি এক্স এবং ওয়াইয়ের ক্ষতিপূরণ দেব না" এমন একটি প্রসঙ্গে বোঝা খুব কঠিন যেখানে সবকিছু ইতিমধ্যে অস্পষ্টভাবে সংজ্ঞায়িত করা হয়েছে। আমি যদি অন্য কোনও সত্তাকে ইনজেক্ট করতে না পারি তবে এটি কীভাবে সঠিকভাবে করা যায় তা দেখতে আরও সহজ।

আমার উদাহরণে ব্যবহারকারী এবং মডারেটর রয়েছে। একজন মডারেটর ব্যবহারকারীদের নিষিদ্ধ করতে পারে তবে ব্যবসায়ের নিয়ম সহ: প্রতিদিন কেবল 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();? কীভাবে নিষেধাজ্ঞা সরিয়ে নেওয়া যায়? আমার কোন ধারণা নাই.


উইকিপিডিয়া নিবন্ধ থেকে: "ডোমেন-চালিত ডিজাইন কোনও প্রযুক্তি বা পদ্ধতি নয়" "সুতরাং এই ধরণের আলোচনা এই ফর্ম্যাটটির জন্য অনুপযুক্ত। এছাড়াও, কেবলমাত্র আপনি এবং আপনার 'বিশেষজ্ঞরা' সিদ্ধান্ত নিতে পারবেন আপনার মডেলটি সঠিক কিনা।

1
@ টড স্মিথ "ডোমেন অবজেক্টগুলিকে অ্যাপ্লিকেশন স্তরটিতে পদ্ধতিগুলি দেখানোর অনুমতিপ্রাপ্ত নয়" এ বিষয়ে দুর্দান্ত একটি বক্তব্য দেয় । প্রথম কোডের নমুনাটি নোট করুন যে ডোমেন অবজেক্টগুলিতে সংগ্রহস্থলগুলি ইনজেকশন না দেওয়ার কীটি হ'ল, সেগুলি অন্য কিছু সংরক্ষণ করে এবং লোড করে। তারা নিজেরাই তা করে না। এটি ডোমেন / মডেল / সত্তা / ব্যবসায়িক অবজেক্টস / বা আপনি যেগুলি কল করতে চান তার পরিবর্তে অ্যাপ্লিকেশনটিকে লজিক নিয়ন্ত্রণের লেনদেন করতে দেয়।
ফাস্টএল

উত্তর:


11

এই প্রশ্নটি কিছুটা বিষয়ভিত্তিক এবং সরাসরি উত্তরের চেয়ে আলোচনার দিকে নিয়ে যায় যা অন্য কেউ উল্লেখ করেছেন - স্ট্যাকওভারফ্লো ফর্ম্যাটের জন্য উপযুক্ত নয়। এটি বলেছিল, আমি মনে করি যে কীভাবে সমস্যাগুলি মোকাবেলা করতে হবে তার জন্য আপনার কয়েকটি কোডেড উদাহরণ প্রয়োজন, তাই আমি আপনাকে কিছু ধারণা দেওয়ার জন্য এটি একটি শট দেব।

আমি প্রথম কথাটি হ'ল:

"ডোমেন অবজেক্টগুলিকে অ্যাপ্লিকেশন স্তরটিতে পদ্ধতিগুলি দেখানোর অনুমতি নেই"

এটি কেবল সত্য নয় - আপনি এটি কোথা থেকে পড়েছেন তা জানতে আগ্রহী। অ্যাপ্লিকেশন স্তরটি ইউআই, ইনফ্রাস্ট্রাকচার এবং ডোমেনের মধ্যে অর্কেস্ট্রেটার এবং তাই স্পষ্টতই ডোমেন সত্তাগুলিতে পদ্ধতি গ্রহণ করা প্রয়োজন।

আমি কীভাবে আপনার সমস্যার মোকাবেলা করব তার একটি কোডেড উদাহরণ লিখেছি। আমি ক্ষমা চেয়ে নিচ্ছি যে এটি সি # তে রয়েছে, তবে আমি পিএইচপি জানি না - আশা করি আপনি এখনও কাঠামোগত দৃষ্টিভঙ্গি থেকে উদ্ধৃতিটি পাবেন।

সম্ভবত আমার করা উচিত হয়নি, তবে আমি আপনার ডোমেন অবজেক্টগুলিকে কিছুটা পরিবর্তন করেছি। নিষেধাজ্ঞার মেয়াদ শেষ হয়ে গেলেও, এটি কিছুটা ত্রুটিযুক্ত অনুভব করতে সাহায্য করতে পারি না যে সিস্টেমে 'নিষিদ্ধ ব্যবহারকারী' ধারণাটি বিদ্যমান।

শুরু করার জন্য, এখানে অ্যাপ্লিকেশন পরিষেবাটি রয়েছে - এটিই ইউআই কল করবে:

public class ModeratorApplicationService
{
    private IUserRepository _userRepository;
    private IModeratorRepository _moderatorRepository;

    public void BanUser(Guid moderatorId, Guid userToBeBannedId)
    {
        Moderator moderator = _moderatorRepository.GetById(moderatorId);
        User userToBeBanned = _userRepository.GetById(userToBeBannedId);

        using (IUnitOfWork unitOfWork = UnitOfWorkFactory.Create())
        {
            userToBeBanned.Ban(moderator);

            _userRepository.Save(userToBeBanned);
            _moderatorRepository.Save(moderator);
        }
    }
}

অনেকটাই অকপট. আপনি নিষেধাজ্ঞার মধ্য দিয়ে মধ্যস্থতাকে আনেন, যে ব্যবহারকারী যিনি মডারেটর নিষিদ্ধ করতে চান এবং ব্যবহারকারীকে 'বান' পদ্ধতিটি কল করে মডারেটরটি পাস করছেন। এটি মডারেটর এবং ব্যবহারকারীর উভয়ের স্থিতি পরিবর্তন করবে (নীচে ব্যাখ্যা করা হয়েছে), যার পরে তাদের সংশ্লিষ্ট রেপোজিটরিগুলির মাধ্যমে অবিচ্ছিন্ন থাকা দরকার।

ব্যবহারকারী শ্রেণি:

public class User : IUser
{
    private readonly Guid _userId;
    private readonly string _userName;
    private readonly List<ServingBan> _servingBans = new List<ServingBan>();

    public Guid UserId
    {
        get { return _userId; }
    }

    public string Username
    {
        get { return _userName; }
    }

    public void Ban(Moderator bannedByModerator)
    {
        IssuedBan issuedBan = bannedByModerator.IssueBan(this);

        _servingBans.Add(new ServingBan(bannedByModerator.UserId, issuedBan.BanDate, issuedBan.BanExpiry));
    }

    public bool IsBanned()
    {
        return (_servingBans.FindAll(CurrentBans).Count > 0);
    }

    public User(Guid userId, string userName)
    {
        _userId = userId;
        _userName = userName;
    }

    private bool CurrentBans(ServingBan ban)
    {
        return (ban.BanExpiry > DateTime.Now);
    }

}

public class ServingBan
{
    private readonly DateTime _banDate;
    private readonly DateTime _banExpiry;
    private readonly Guid _bannedByModeratorId;

    public DateTime BanDate
    {
        get { return _banDate;}
    }

    public DateTime BanExpiry
    {
        get { return _banExpiry; }
    }

    public ServingBan(Guid bannedByModeratorId, DateTime banDate, DateTime banExpiry)
    {
        _bannedByModeratorId = bannedByModeratorId;
        _banDate = banDate;
        _banExpiry = banExpiry;
    }
}

ব্যবহারকারীর জন্য আক্রমণকারীটি হ'ল নিষিদ্ধ করার সময় তারা কিছু নির্দিষ্ট ক্রিয়া সম্পাদন করতে পারে না, সুতরাং বর্তমানে কোনও ব্যবহারকারী নিষিদ্ধ হয়েছে কিনা তা আমাদের সনাক্ত করতে সক্ষম হওয়া দরকার। এটি অর্জনের জন্য ব্যবহারকারীরা পরিবেশন নিষিদ্ধের একটি তালিকা বজায় রাখে যা মডারেটররা জারি করেছে। ইসবানোড () পদ্ধতিটি যে কোনও পরিবেশন নিষেধাজ্ঞার মেয়াদ এখনো শেষ হয়নি তা পরীক্ষা করে। যখন বান () পদ্ধতিটি কল করা হয়, তখন এটি প্যারামিটার হিসাবে একটি মডারেটর গ্রহণ করে। এটি তখন মডারেটরকে নিষেধাজ্ঞা জারি করতে বলে:

public class Moderator : User
{
    private readonly List<IssuedBan> _issuedbans = new List<IssuedBan>();

    public bool CanBan()
    {
        return (_issuedbans.FindAll(BansWithTodaysDate).Count < 3);
    }

    public IssuedBan IssueBan(User user)
    {
        if (!CanBan())
            throw new InvalidOperationException("Ban limit for today has been exceeded");

        IssuedBan issuedBan = new IssuedBan(user.UserId, DateTime.Now, DateTime.Now.AddDays(7));

        _issuedbans.Add(issuedBan); 

        return issuedBan;
    }

    private bool BansWithTodaysDate(IssuedBan ban)
    {
        return (ban.BanDate.Date == DateTime.Today.Date);
    }
}

public class IssuedBan
{
    private readonly Guid _bannedUserId;
    private readonly DateTime _banDate;
    private readonly DateTime _banExpiry;

    public DateTime BanDate { get { return _banDate;}}

    public DateTime BanExpiry { get { return _banExpiry;}}

    public IssuedBan(Guid bannedUserId, DateTime banDate, DateTime banExpiry)
    {
        _bannedUserId = bannedUserId;
        _banDate = banDate;
        _banExpiry = banExpiry;
    }
}

মডারেটরের পক্ষে আক্রমণকারীটি হ'ল এটি কেবল প্রতিদিন 3 টি নিষেধাজ্ঞা জারি করতে পারে। সুতরাং, যখন ইস্যুবান পদ্ধতিটি ডাকা হয়, এটি পরীক্ষা করে যে মডারেটরের তার জারি করা নিষিদ্ধের তালিকায় আজকের তারিখ সহ 3 জারি নিষেধাজ্ঞাগুলি নেই। এটি তার তালিকায় নতুন জারি করা নিষেধাজ্ঞা যুক্ত করে এবং এটি ফেরত দেয়।

বিষয়বহুল, এবং আমি নিশ্চিত যে কেউ এই পদ্ধতির সাথে দ্বিমত পোষণ করবে তবে আশা করি এটি আপনাকে একটি ধারণা দেয় বা কীভাবে এটি একসাথে ফিট হতে পারে।


1

আপনার সমস্ত যুক্তি সরিয়ে নিন যা কোনও পরিষেবা স্তরতে রাষ্ট্র পরিবর্তিত করে (উদা: মডারেটর সার্ভিস) যা সত্তা এবং রেপোজিটরি উভয়ই সম্পর্কে জানে।

ModeratorService.BanUser(User, UserBanRepository, etc.)
{
    // handle ban logic in the ModeratorService
    // update User object
    // update repository
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.