Лучшие практики инициализации дерева объектов Spring MVC - PullRequest
7 голосов
/ 18 декабря 2008

Если у меня есть объект поддержки формы, который имеет сложное дерево объектов - скажем, Person, у которого есть объект Contact Info, у которого есть объект Address, который имеет несколько строк - кажется, что объект должен быть полностью заполнены компонентами объектов, прежде чем я могу связать с ним. Поэтому, если я создаю нового Person, мне нужно убедиться, что в нем все компоненты компонента заполнены, и если я получаю Person из базы данных, мне нужно убедиться, что любые объекты, которые не являются заполняется из базы данных, заполняется пустыми объектами.

Первый вопрос, конечно - я прав в своих предположениях выше? Кажется, что, если я пытаюсь привязать к person.contactInfo.homeAddress.street и нет ContactInfo, я получаю исключение нулевого указателя.

Во-вторых, каков наилучший способ инициализации моего объекта. Я могу придумать пару подходов. Одним из них является инициализация всех объектов-членов при объявлении:

public class Person {
     String name;
     ContactInfo contactInfo = new ContactInfo();
     //getters, setters, etc.
}

public class ContactInfo {
     String phone;
     Address homeAddress = new Address();
}

и пр.

Другой подход состоит в том, чтобы иметь PersonFactory, который инициализирует все (или иметь фабричный метод Person.getInstance, который инициализирует все).

В случае извлечения Person из базы данных, первый подход решит проблему (т. Е. Если этот конкретный человек не имеет адреса в базе данных, объект все равно будет иметь Address), но это будет означать создавая каждый объект дважды. Не уверен, как справиться с этим иначе, за исключением того, чтобы DAO явно заполнял все, даже если ничего не было получено из базы данных. Или дать фабрике способ пройти через объект и «заполнить» все, что отсутствует.

Предложения

Ответы [ 4 ]

4 голосов
/ 23 января 2009

Называйте это излишним, если хотите, но в действительности мы в итоге создали универсальную фабрику, которая будет принимать любой объект и использовать отражение, чтобы (рекурсивно) найти все нулевые свойства и создать экземпляр объекта правильного типа. Я сделал это с помощью Apache Commons BeanUtils.

Таким образом, вы можете взять объект, который вы могли получить из различных источников (DAO, десериализация из XML и т. Д.), Передать его через эту фабрику и использовать его как объект поддержки форм, не беспокоясь о том, что вам нужно для привязки может быть нулевым.

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

3 голосов
/ 19 декабря 2008

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

В случае, если вы дадите здесь, я бы, вероятно, поместил инициализацию в getter, чтобы дочерний объект создавался только тогда, когда он фактически будет использоваться, то есть: когда вызывается getter и только тогда, когда он нулевой. *

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

Когда дело доходит до отношений один ко многим, я обычно хожу на ленивую загрузку. Hibernate возьмет на себя это за вас, но если вы используете свою собственную, тогда вам просто нужна специальная реализация List, которая вызывает соответствующий DAO при вызове любого из методов, относящихся к его содержимому.

Единственное исключение из этого поведения с отношениями «один ко многим» - это когда у вас есть список родительских объектов, для которых вы хотите выполнить итерацию, и для каждого родителя, который вы хотите выполнить для своих дочерних элементов. Очевидно, что производительность будет плохой, потому что вы будете делать n + 1 вызовы в БД, когда вы действительно сможете сделать это с 2 вызовами.

1 голос
/ 19 декабря 2008

Я придерживался подхода метода Factory (не фанат использования для него отдельного класса, для меня более логично иметь его в статическом методе, чтобы он был в одном месте). У меня есть что-то вроде -

public static Person getInstanceForContactInfoForm() {
      ContactInfo contactInfo = ContactInfo.getInstanceForContactInfoForm();

      Person person = new Person(contactInfo);
      // set whatever other properties you need for Person
      // just enough to 1-render the form and 2-avoid any exceptions
      return person;
}

Если я загружаю Person из базы данных, у меня есть метод в классе Person, называемый что-то вроде "initalizeForContactInfoForm" или что-то в этом роде. После загрузки Person из базы данных я вызову этот метод на уровне Service в методе, который вызывается методом Spring MVC, который возвращает объект поддержки формы.

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

1 голос
/ 19 декабря 2008

Полагаю, вы говорите о чем-то вроде < form:input path="person.contactInfo.homeAddress.street"/>? Не ясно для меня, но при условии, что я прав :):

1) Да, когда вы пишете person.contactInfo.homeAddress.street , читайте person.getContactInfo().getHomeAddress().getStreet(). Если объекты ContactInfo, HomeAddress или Street имеют значение null, вызов одного из их методов вызывает исключение NullPointException.

2) Я обычно инициализирую объекты-члены при объявлении, как в фрагменте кода. Не вижу преимущества фабричного класса в выполнении работы, если значения инициализации не являются обязательными. Я не вижу четкой проблемы, когда вы вынуждены дважды создавать Человека ... но я могу быть уставшим;)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...