我想知道我是否遗漏了有关 Java Beans 的内容。我喜欢我的对象在构造函数中尽可能多地进行初始化,并且具有最少数量的突变体。Beans 似乎直接反对这一点,并且通常感觉很笨重。由于不将对象构建为 Bean,我错过了哪些功能?
5 回答
听起来你在正确的轨道上。不是你错过了 Java Beans 的要点,而是其他程序员在滥用它们。
Java Beans 规范旨在与可视化工具一起使用。这个想法是应用程序设计人员能够以交互方式配置对象的实例,然后序列化(或为配置的 bean 生成代码),以便可以在运行时重构它;目的是它不会在运行时发生突变。
不幸的是,许多开发人员不了解访问器违反封装。他们使用结构而不是对象。他们没有看到其他类,甚至是其他包,依赖于类的数据成员有什么问题。
当然,您通常需要配置对象的实例。只是这应该通过某种配置功能来完成。这可能是一个依赖注入容器、一个“BeanBox”风格的可视化工具,或者只是读取您手动编写的 JSON、XML 或属性文件。关键是在运行时这些对象实际上是不可变的;客户端只是调用他们的操作,他们不访问他们的属性。
我喜欢我的对象在构造函数中尽可能多地进行初始化,并且具有最少数量的突变体。
偏爱不可变对象是明智的选择。然而,bean 的好处是框架/工具/库可以在运行时确定类的属性,而无需您实现特定的接口。
例如,假设您有一个 Person bean 的集合,并且每个 bean 都有名称、年龄、身高等属性。
您可以使用以下代码按名称(例如)对这个 bean 集合进行排序:
Collection<Person> myCollection = // initialise and populate the collection
Comparator nameCompare = new BeanComparator("name");
Collections.sort(myCollection, nameCompare);
BeanComparator类知道如何从每个对象中提取“名称”属性,因为遵循 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 只是一个简单的约定,它允许在运行时(通常通过工具或框架)动态地发现类的属性,当不方便/不可能先验地知道可能提供的属性时。
我同意最小化可变性是一件好事的想法。正如已经指出的,JavaBeans 的优点是它们很容易被框架处理。
为了充分利用“两全其美”,我认为一个不错的选择是使用Builder 模式,稍微修改 Builder 以符合 JavaBeans 标准。因此,如果您需要一个要求您的类符合 JavaBeans 标准的框架功能,您可以使用 Builder 代替实际的类。
当你听到“bean”这个词时,期望看到的是某种“容器”。任何类型的 JavaBean 的想法是为可以在运行时添加和操作的组件提供统一的接口约定。普通 JavaBean 只是其中最简单的示例:它提供了所有接口可能性并且是可序列化的,这意味着您可以创建 bean 的实例、修改它们、保存它们并重新加载它们。
很久很久以前,我编写了一个 Java 编辑器,它包含一个表示文本字符串的简单“数据库”,并有一个使用 bean 的“插件架构”。您可以通过将 bean 从 bean 存储箱中拖出并将其放在编辑器上来向编辑器添加行为;一旦你这样做了,行为(例如,Cntl-T 在光标处转置字符)在编辑器中自动可用。bean 有一个已知的接口——它们知道如何向容器询问其数据结构和一个 doSomething() 方法——并且容器知道动态加载类文件、实例化对象并将其访问权限设置为数据库。
顺便说一句,访问器违反封装并不一定是真的。然而,确实,仅仅因为你有一个成员,你就不需要为它提供 get 和 set 方法。JavaBean 规范对此有点不清楚;关键是为那些需要在对象“合同”中的东西提供getter和setter。
在将内省和反思添加到语言中并真正理解之后,对这些约定的需求有所减少;在早期的 Java 中,您需要有一个约定来查找方法。