Spring MVC 3 — привязка неизменяемого объекта к форме

#spring #spring-mvc #domain-driven-design #immutability

#spring #spring-mvc #дизайн, управляемый доменом #неизменность

Вопрос:

У меня есть несколько тщательно протестированных и тщательно обработанных классов моделей DDD, с окончательными неизменяемыми инвариантами и проверками целостности. Создание экземпляра объекта происходит с помощью соответствующих конструкторов, статических фабричных методов и даже с помощью конструкторов.

Теперь я должен предоставить форму Spring MVC для создания новых экземпляров некоторых классов.

Мне кажется (я не эксперт), что я должен предоставить пустые конструкторы и установщики атрибутов для всех вспомогательных классов формы, которые я хочу привязать.

Итак, что мне делать?

Создание анемичных объектов, предназначенных для поддержки формы, и передача информации в мою модель предметной области (так много для принципа DRY …) вызывает соответствующие методы / конструктор?

Или есть механизмы, которые я пропустил, которые могут спасти мой день? 🙂

Заранее благодарю вас за вашу мудрость!

Ответ №1:

Объекты, которые используются для привязки к слоям представления, обычно называются моделями представления, и они представляют собой DTO, предназначенные для отображения данных, отображаемых из объектов домена, а затем отображения пользовательского ввода обратно в объекты домена. Модели представления обычно выглядят очень похожими на объекты домена, которые они представляют, однако есть некоторые важные различия:

  1. Данные из объектов домена могут быть сглажены или иным образом преобразованы в соответствии с требованиями данного представления. Управление отображением в простых объектах проще, чем отображениями в среде представления, такой как MVC. Так проще отлаживать и обнаруживать ошибки.

  2. Для данного представления могут потребоваться данные из нескольких объектов домена — может не быть ни одного объекта домена, который соответствует требованиям представления. Модель представления может быть заполнена несколькими объектами домена.

  3. Модель представления обычно разрабатывается с учетом конкретной среды представления и, как таковая, может использовать атрибуты, специфичные для среды, для привязки и проверки на стороне клиента. Как вы заявили, типичным требованием является конструктор без параметров, который подходит для модели представления. Опять же, гораздо проще тестировать и управлять моделью представления, чем каким-то сложным механизмом отображения.

Модели представлений, по-видимому, нарушают принцип DRY, однако после более пристального взгляда ответственность модели представления отличается, поэтому с учетом принципа единой ответственности целесообразно иметь два класса. Кроме того, взгляните на эту статью, в которой обсуждается ошибка повторного использования, часто приводящая к принципу DRY.

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

Также обратите внимание, что существуют библиотеки, которые пытаются упростить сопоставление между моделями представлений и объектами домена, например AutoMapper для .NET Framework.

Комментарии:

1. Хотя я не слишком забочусь о DRY, мне также не нравятся ненужные слои, и было бы неплохо, если бы я мог привязываться к объекту домена, когда объект достаточно хорошо напоминает структуру представления. Даже для умеренно сложных сценариев неплохо отделить модели представления от объектов домена, но для очень простых сценариев («FirstName», «MiddleName», «LastName» с очень простым объектом Name, доступным в домене) наличие дополнительного класса модели представления просто кажется расточительной работой / шаблоном. К сожалению, я не вижу особой альтернативы.

Ответ №2:

Да, вам нужно будет создать объекты, чтобы форма принимала все входные данные, и обновить вашу модель с помощью этих объектов за одну операцию.

Но я не буду называть эти объекты анемичными (особенно, если вы выполняете DDD). Эти объекты представляют собой одну единицу работы. Так что это тоже концепции домена!

Ответ №3:

Я решил это, создав интерфейс DTO:

 public interface DTO<T> {
    T getDomainObject();

    void loadFromDomainObject(T domainObject);
}

public class PersonDTO implements DTO<Person> {
    private String firstName;
    private String lastName;

    public PersonDTO() {
        super();
    }

    // setters, getters ...

    @Override
    public Person getDomainObject() {
        return new Person(firstName, lastName);
    }

    @Override
    public void loadFromDomainObject(Person person) {
        this.firstName = person.getFirstName();
        this.lastName = person.getLastName();
    }

    // validation methods, view formatting methods, etc
}
  

Это также предотвращает утечку информации о проверке представления и форматировании в модель домена. Мне действительно не нравится наличие специфичных для Spring (или других специфичных для фреймворка) аннотаций (@Value и т. Д.) И аннотаций javax.validation в объектах моего домена.