7

如果我有一个具有复杂对象树的表单支持对象——比如说一个人,它有一个联系信息对象,一个地址对象有一堆字符串——似乎该对象需要用组件完全填充对象之前我可以绑定到它。因此,如果我要创建一个新的 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)。

在从数据库中检索人员的情况下,第一种方法将解决问题(即,如果此特定人员在数据库中没有地址,则该对象仍然有一个地址),但这意味着创建每个对象两次。不知道如何处理这个问题,除了让 DAO 显式填充所有内容,即使没有从数据库中检索到任何内容。或者给工厂一种方法来遍历对象并“填充”任何缺少的东西。

建议?

4

4 回答 4

4

如果您愿意,可以称其为矫枉过正,但我​​们实际上最终做的是创建一个通用工厂,它将获取任何对象并使用反射(递归)查找所有空属性并实例化正确类型的对象。我使用 Apache Commons BeanUtils 做到了这一点。

通过这种方式,您可以获取可能从各种来源(DAO、XML 反序列化等)获得的对象,将其传递给该工厂,并将其用作表单支持对象,而不必担心绑定所需的东西可能为空。

诚然,这意味着实例化给定表单可能不需要的属性,但在我们的例子中通常并不适用。

于 2009-01-23T17:25:41.863 回答
3

我通常会确保对象已完全初始化 - 它使使用对象更加简单,并避免您在整个代码中分散空检查。

在您在这里给出的情况下,我可能会将初始化放在 getter 中,因此子对象仅在实际使用时才被实例化,即:当 getter 被调用时,只有当它为 null 时才被实例化。

在从具有一对一关系的数据库加载方面,我通常会进行连接并加载很多内容。性能影响通常很小,但您应该知道可能存在影响。

当涉及到一对多关系时,我通常会选择延迟加载。Hibernate 会为您解决这个问题,但如果您自己滚动,那么您只需要一个 List 的自定义实现,它在调用与其内容相关的任何方法时调用适当的 DAO。

这种具有一对多关系的行为的一个例外是,当您有一个要迭代的父对象列表以及每个要迭代其子对象的父对象时。显然,性能会很糟糕,因为当您实际上可以通过 2 次调用来完成时,您会对数据库进行 + 1 次调用。

于 2008-12-18T21:17:10.263 回答
1

我猜你在谈论类似的东西 < form:input path="person.contactInfo.homeAddress.street"/>?我不清楚,但假设我是对的:):

1)是的,当你写的时候person.contactInfo.homeAddress.street ,读person.getContactInfo().getHomeAddress().getStreet()。如果 ContactInfo 或 HomeAddress 或 Street 对象为 null,则调用其中一种方法会引发 NullPointException。

2)我通常在声明时初始化成员对象,就像在代码片段中一样。如果初始化值是无条件的,则看不到工厂类完成这项工作的好处。我没有清楚地看到您被迫两次创建 Person 的问题……但我可能累了;)

于 2008-12-18T21:16:34.320 回答
1

我已经采用了工厂方法方法(不喜欢为它使用单独的类,对我来说,将它放在静态方法中更有意义,所以它都在一个地方)。我有类似的东西 -

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 类中有一个名为“initializeForContactInfoForm”之类的方法。从数据库加载 Person 后,我将在返回 Form Backing Object 的 Spring MVC 方法调用的方法中调用 Service 层中的此方法。

我不认为这是一个真正的惯例,这只是我自己制定的一种方法。我真的不知道有什么缺点,所以如果有人不同意,请告诉我......

于 2008-12-18T21:47:09.953 回答