2012-03-19 3 views
4

Пусть класс MailConfiguration Задавая параметры для отправки почты:Хорошая практика для проверки неизменных ценностей объекты

public class MailConfiguration { 

    private AddressesPart addressesPart; 

    private String subject; 

    private FilesAttachments filesAttachments; 

    private String bodyPart; 

    public MailConfiguration(AddressesPart addressesPart, String subject, FilesAttachments filesAttachements, 
    String bodyPart) { 
    Validate.notNull(addressesPart, "addressesPart must not be null"); 
    Validate.notNull(subject, "subject must not be null"); 
    Validate.notNull(filesAttachments, "filesAttachments must not be null"); 
    Validate.notNull(bodyPart, "bodyPart must not be null"); 
    this.addressesPart = addressesPart; 
    this.subject = subject; 
    this.filesAttachements = filesAttachements; 
    this.bodyPart = bodyPart; 
    } 
    // ... some useful getters ...... 

} 

Итак, я использую два значение объектов: AddressesPart и FilesAttachment.

тезисов два значения объект имеет сходные структуры, так что я только собирается выставить здесь AddressesPart:

public class AddressesPart { 

    private final String senderAddress; 

    private final Set recipientToMailAddresses; 

    private final Set recipientCCMailAdresses; 

    public AddressesPart(String senderAddress, Set recipientToMailAddresses, Set recipientCCMailAdresses) { 
    validate(senderAddress, recipientToMailAddresses, recipientCCMailAdresses); 
    this.senderAddress = senderAddress; 
    this.recipientToMailAddresses = recipientToMailAddresses; 
    this.recipientCCMailAdresses = recipientCCMailAdresses; 
    } 

    private void validate(String senderAddress, Set recipientToMailAddresses, Set recipientCCMailAdresses) { 
    AddressValidator addressValidator = new AddressValidator(); 
    addressValidator.validate(senderAddress); 
    addressValidator.validate(recipientToMailAddresses); 
    addressValidator.validate(recipientCCMailAdresses); 
    } 

    public String getSenderAddress() { 
    return senderAddress; 
    } 

    public Set getRecipientToMailAddresses() { 
    return recipientToMailAddresses; 
    } 

    public Set getRecipientCCMailAdresses() { 
    return recipientCCMailAdresses; 
    } 

} 

И валидаторы: AddressValidator

public class AddressValidator { 

    private static final String EMAIL_PATTERN 
    = "^[_A-Za-z0-9-]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$"; 

    public void validate(String address) { 
    validate(Collections.singleton(address)); 
    } 

    public void validate(Set addresses) { 
    Validate.notNull(addresses, "List of mail addresses must not be null"); 
    for (Iterator it = addresses.iterator(); it.hasNext();) { 
     String address = (String) it.next(); 
     Validate.isTrue(address != null && isAddressWellFormed(address), "Invalid Mail address " + address); 
    } 
    } 

    private boolean isAddressWellFormed(String address) { 
    Pattern emailPattern = Pattern.compile(EMAIL_PATTERN); 
    Matcher matcher = emailPattern.matcher(address); 
    return matcher.matches(); 
    } 
} 

Таким образом, у меня есть два вопросы:

1) Если по каким-то причинам позже мы хотим проверить адрес электронной почты (например, чтобы включить/исключить некоторые псевдонимы, соответствующие существующему почтовому списку), следует ли я представить вид IValidator в качестве параметра конструктора? как следующий, а не в результате чего конкретной зависимости (как я сделал):

public AddressValidator(IValidator myValidator) { 
    this.validator = myValidator; 
} 

В самом деле, это будет соблюдать принцип D твердого принципа: инъекции зависимостей.

Однако, если мы будем следовать этому логическому, будет ли большинство объектов ценностей иметь абстрактный валидатор, или это просто перехитрить большую часть времени (думая YAGNI?)?

2) Я прочитал в некоторых статьях, чем в отношении DDD, все проверки должны присутствовать и присутствовать только в Aggregate Root, означает в этом случае MailConfiguration.

Я прав, если учесть, что неизменные объекты никогда не должны находиться в состоянии несвязывания? Таким образом, будет ли валидация в конструкторе, как я сделал, предпочтительнее в соответствующем объекте (и, таким образом, избегая того, чтобы агрегат беспокоился о проверке его «детей»?

ответ

2

Я не совсем уверен, если я последую за вами на 100%, но в один конец для обработки неизменяемых объектов разрешается создавать только в том случае, если они действительны, это использовать Essence Pattern.

Вкратце, идея состоит в том, что родительский класс содержит статический завод, который создает неизменные экземпляры самого себя на основе экземпляров внутренняя сущность «сущность». Внутренняя сущность изменчива и позволяет создавать объекты, поэтому вы можете складывать куски во время своей работы и также могут быть проверены на этом пути.

Принципы SOLID и хороший DDD соблюдаются, поскольку родительский неизменный класс по-прежнему выполняет только одну вещь, но позволяет другим создавать его через «сущность».

Для примера см. Ldap extension в библиотеке Spring Security.

+0

Спасибо :) Я прочитал вашу статью, и особенно это более подробно: http://hillside.net/plop/plop98/final_submissions/P10.pdf – Mik378

+0

Да, я связан с тем, что я сделал, поскольку это более практичный пример а также связан с исходной статьей по шаблону. – cdeszaq

+0

И в моем случае, когда MailConfiguration обертывает AddressesPart. Имеет ли смысл размещать AddressPartEssence внутри AddressesPart и MailConfigurationEssence внутри MailConfiguration? Или просто в AddressesPart достаточно, чтобы избежать сложного решения? – Mik378

1

Некоторые наблюдения в первую очередь.

Почему нет дженериков? J2SE5.0 вышел в 2004 году.

Текущая версия Java SE имеет стандарт Objects.requiresNonNull. Немного глотка, и капитализация ошибочна. Также возвращает переданный объект, поэтому не требуется отдельная строка.

this.senderAddress = requiresNonNull(senderAddress); 

Ваши классы не совсем неизменяемы. Они являются подклассами. Также они не делают безопасной копии своих изменяемых аргументов (Set s - стыд, в библиотеке Java еще нет неизменных типов коллекций). Примечание. Скопируйте перед проверкой.

this.recipientToMailAddresses = validate(new HashSet<String>(
     recipientToMailAddresses 
    )); 

Использование ^ и $ в регулярном выражении немного вводит в заблуждение.

Если проверка изменяется, то есть два очевидных (вменяемые) выборы:

  • только сделать широчайший изменения в этом классе. Подтвердите более конкретно в контексте, который он будет использоваться.
  • Просьба использовать валидатор и использовать его как собственность. Чтобы быть полезным, клиентский код должен был бы проверить и сделать что-то разумное с этой информацией, что маловероятно.

Не имеет смысла передавать валидатор в конструктор, а затем отбрасывать его. Это усложняет конструктор. Поместите его в статический метод, если нужно.

Входящий экземпляр должен проверить, что его аргумент действителен для конкретного использования, но не должен перекрываться с классами, гарантируя, что они в целом действительны. Где это закончится?

+0

Спасибо за эти замечания :) Я вынужден использовать JDK 1.4, так как я работаю для приложения в инвестиционном банке, который все еще находится в 1.4 ... Вы сказали, что установка валидатора в параметр конструктора объекта значения будет сложнее, но с статический метод, объект действительно может быть использован и использован с ... null validator? опасно, если создание не является атомным? Возможно, я не очень хорошо понимаю ваш подход, не могли бы вы привести краткий пример? – Mik378

+0

1.4 был заменен семь или восемь лет назад. Бьюсь об заклад, их объявления о работе запрашивают передовые навыки, а затем перечисляют технологии с 1990-х годов. Если вы используете статический метод создания, вы можете выполнить проверку прежде, чем объект будет даже построен. –

3

В DDD есть базовый шаблон, который отлично выполняет работу по проверке и сборке объектов для создания нового: Factory.

Я читал в некоторых статьях, чем в отношении DDD, вся валидация должна присутствовать и присутствуют только в агрегированном Root

Я категорически не согласен с этим. Там может быть логик проверки в широком диапазоне мест в DDD:

  • Validation после создания, выполняемого заводом
  • Enforcement инвариантов агрегатных, в обычно делаются в Совокупном Root
  • Проверка охватывает accross несколько объекты можно найти в доменных службах.
  • т.д.

Кроме того, я нахожу это забавным, что вы потрудились создать объект AddressesPart значение -Какой это хорошая вещь, не считая создания EMAILADDRESS объекта значение в первую очередь. Я думаю, что это довольно сложно усложняет ваш код, потому что нет инкапсулированного представления о том, что такое адрес электронной почты, поэтому AddressesPart (и любой объект, который будет манипулировать адресами, если на то пошло) вынужден иметь дело с AddressValidator для выполнения проверки его адресов. Я думаю, что это не должно быть его ответственностью, а не адресом AddressFactory.

0

Хотя старый вопрос, но для тех, кто споткнулся об этом предмете, пожалуйста, держите его простым с POJO (обычными старыми объектами Java). Что касается валидаций, то нет единственной истины, потому что для чистого DDD вам нужно постоянно учитывать контекст. Например, пользователь, не имеющий данных кредитной карты, может и должен иметь возможность создавать учетную запись.Но данные кредитной карты необходимы при проверке на странице корзины покупок. Как это прекрасно решено DDD, это перемещение битов и кусков кода в объекты Entities and Value Objects, где оно, естественно, принадлежит.

В качестве второго примера, если адрес никогда не должен быть пустым в контексте задачи уровня домена, тогда объект значения адреса должен принудительно включить это утверждение внутри объекта вместо того, чтобы просить стороннюю библиотеку проверить, является ли определенный объект значения имеет значение null или нет.

Кроме того, адрес как объект с автономными значениями не дает большого значения по своему усмотрению по сравнению с ShippingAddress, HomeAddress или CurrentResidentialAddress ... вездесущим языком, другими словами, имена передают их намерения.