Свойства на домейн обекти и капсулиране

Имам имейл обект с две свойства, етикет и стойност. Системният потребител трябва да потвърди имейла си, преди да може да го използва в системата. Процесът на проверка е много прост:

  1. Задайте код за активиране на имейла
  2. Изпратете имейл с кода за активиране, за да проверите дали имейлът е валиден

Имейл обектът изглежда по следния начин:

class Email {
    String label
    String value
    EmailStatus status
    String activationCode

    boolean requestVerification() {
        // Set the activationCode that will be refereced to change the email status 
        this.activationCode = UUID
        // Raise an event to send a notification email by a communication service
        EventManager.fire('emailVerificationRequest',this)
    }

Всичко работи добре, с изключение на това, че свойството activationCode не се чувства правилно в обекта Email. Той по никакъв начин не описва състоянието на обекта и се използва само в процеса на валидиране на имейл. Затова промених кода си, за да въведа нов обект, наречен ActivationToken. Обектът ще се използва за капсулиране на кода за активиране. Ето новата версия на имейл обекта

 class Email {
    String label
    String value
    EmailStatus status

    boolean requestVerification() {
        new ActivationToken(target:this,code:UUID,expiryDate:new Date()).save()
        // Raise an event to send a notification email by a communication service
        EventManager.fire('emailVerificationRequest',this)
    }

 class ActivationToken {
    Email target
    String code
    Date expiryDate
 }
  1. Това добър дизайн на домейн ли е или усложнявам обекта си за нищо
  2. Дали методът requestVerification принадлежи към имейл обекта на първо място или трябва да бъде поставен другаде; в услуга или в процес.
  3. Има ли някакъв модел на проектиране, който мога да следвам, за да се справя с подобни проблеми

Актуализация

Исках да обясня защо запазих метода requestVerfication като част от обекта на имейл домейна дори след втория подход за рефакторинг.

Имам отдалечен интерфейс, който взаимодейства директно с обекти на домейн чрез диспечер по следния начин:

remote://email/6/do/requestVerification

Първоначално исках да запазя цялата комуникация с бекенда канализирана през обектите на домейна и ако има нужда от взаимодействие, да речем, с услуга, използвах IOC, за да го инжектирам в обекта на домейн и да използвам обекта на домейн като прокси. Разделянето между отдалечения интерфейс и обекта на домейна изглеждаше чисто, но това се оказа много лоша идея, тъй като превзема дизайна на домейна и въвежда безполезна зависимост към външен обект (в този случай EmailVerificationService), който няма нищо общо с поведението или аспектите на състоянието на обекта на домейна

Другото решение за разрешаване на това може да бъде запазването на метода requestVerification в услуга, където той естествено принадлежи, и въвеждането на нов синтаксис в комуникационния протокол като:

 remote://service/email/do/requestVerification

Какво мислите момчета?

Благодаря ти

-кен


person ken    schedule 03.09.2010    source източник


Отговори (3)


Лично аз намирам и двата подхода за приемливи, но предпочитам втория. Това, което бих използвал, за да определя кой подход, ще бъде приносът на експерта по домейна. Когато моделирате домейна, кодът за активиране беше ли нещо изрично част от изискването или имате причина да го поддържате, след като имейл акаунтът е валидиран? Ако нямате изрична причина да изберете първия си подход, аз бих се придържал към втория.

По отношение на вашите индивидуални въпроси:

  1. Не бих стигнал толкова далеч, че да го считам за усложняване на вашия обект, повече за абстрахиране на проблемите на ниво услуга от домейна. Да, това е повече код и повече работа, но вероятно е по-добрият подход - освен ако нямате изрична причина да използвате оригиналния подход.

  2. Както беше споменато, наистина мисля, че това е отговорност на ниво услуга и трябва да бъде в някакъв вид EmailVerificationService. В самия модел на домейна ви интересува само дали имейлът е валиден, а не начинът, по който е валидиран.

  3. Според мен вече използвате най-добрия възможен подход. Шината за събития със събития, генерирани от обекта на домейна, е чиста и надеждна.

person Joseph Ferris    schedule 03.09.2010
comment
Моля, вижте актуализацията на моя въпрос, която обяснява причината, поради която не избрах сервизния подход на първо място. Вашите коментари са много ценени. Благодаря ти - person ken; 03.09.2010

Предприехте правилните стъпки при разделянето на Email от ActivationToken - концептуално те са отделни неща (между другото, бих използвал EmailActivationToken за яснота ).

Обикновено EmailVerificationService ще се използва за капсулиране на логиката за проверка.

person Vijay Patel    schedule 03.09.2010
comment
Моля, вижте актуализацията на моя въпрос, която обяснява причината, поради която не избрах сервизния подход на първо място. Вашите коментари са много ценени. Благодаря ти - person ken; 03.09.2010

Мисля, че е добра идея да капсулирате функционалността в ActivationToken. Но чрез инициализиране на ActivationToken в рамките на класа Email вие сте създали скрита зависимост от външен ресурс. Това на практика прави Email труден за модулно тестване и повторно използване от други клиенти, които имат друга схема за активиране.

Вместо това може да искате да използвате модела Инжектиране на зависимост/инверсия на контрол, за да инжектирате ActivationToken в Email клас. Това ви позволява да инжектирате различни стратегии за активиране и се отваря за лесно модулно тестване на класа Email.

За да направите това, ви е необходим интерфейс за ActivationToken и конструкторът на класа Email трябва да се позовава на обект, изпълняващ този интерфейс:

interface IActivationToken
{
   void Save(object target, string code, DateTime date);
}

class Email
{
    IActivationToken token;
    // Other properties go here.

    public Email(IActivationToken token)
    {
        this.token = token;
    }

    boolean RequestVerification() 
    {    
        token.Save(this, code, date);        
        // Raise an event to send a notification email by a communication service    
        EventManager.fire('emailVerificationRequest', this)    
    }    
}

Сега класът Email няма скрити зависимости от външни ресурси.

person Jakob Christensen    schedule 03.09.2010
comment
Моля, вижте актуализацията на моя въпрос, която обяснява причината, поради която не избрах сервизния подход на първо място. Вашите коментари са много ценени. Благодаря ти - person ken; 03.09.2010