我在想,是不是我对Java Beans有所遗漏。我喜欢让我的对象在构造函数中尽可能地完成初始化,并尽量减少可变性。Beans似乎直接违反了这一点,并且通常感觉很笨重。如果我不将对象构建为Beans,我会错过哪些功能?
看起来你走在了正确的道路上。不是你没有理解 Java Beans 的重点,而是其他程序员误用了它们。
Java Beans 规范是为了与可视化工具一起使用而设计的。其想法是应用程序设计人员可以交互式地配置一个对象实例,然后将配置的 Bean 序列化(或生成代码),以便在运行时进行重构;其目的是在运行时不会被改变。
不幸的是,很多开发者不理解访问器违反了封装性。他们使用结构体而不是对象。他们认为让其他类甚至其他包依赖于类的数据成员没有任何问题。
当然,你通常需要配置你的对象实例。只是这应该通过某种配置特性完成。这可能是依赖注入容器、"BeanBox" 风格的可视化工具,或者仅仅是阅读你手动编写的 JSON、XML 或属性文件。关键是在运行时这些对象是有效地不可变的;客户端只调用它们的操作,而不访问它们的属性。
我喜欢让对象在构造函数中尽可能多地进行初始化,并且最小化可变的特征。
倾向于不可变的对象是一个明智的选择。然而,JavaBean 的好处在于框架/工具/库可以在运行时确定类的属性,而无需您实现特定的接口。
例如,假设您有一个 Person bean 集合,每个 bean 都有名称、年龄、身高等属性。
您可以使用以下代码按名称对这个 bean 集合进行排序:
Collection<Person> myCollection = // initialise and populate the collection
Comparator nameCompare = new BeanComparator("name");
Collections.sort(myCollection, nameCompare);
BeanComparator 类知道如何从每个对象中提取“name”属性,因为遵循了 Java Beans 约定,即您无需实现诸如以下接口的“开销”:
interface Nameable {
public String getName();
public void setName(String name);
}
Spring MVC中的另一个例子是一个用于存储请求URL参数的bean。可以在Web控制器(在Struts中称为“Action”)中定义如下:
public ModelAndView searchUsers(UserSearchCriteria criteria) {
// implementation omitted
}
由于 UserSearchCriteria 预期是一个 JavaBean,如果请求 URL 包含参数,例如 maxItems=6
,Spring 框架会“知道”它应该调用一个带有以下签名的方法:
void setMaxItems(int maxItems);
本质上,JavaBeans只是一种简单的约定,允许在运行时动态地发现类的属性(通常是通过工具或框架实现),当无法事先知道可能提供的属性时使用。