Java Beans的一个好的应用案例是什么?

3
我刚看到Java Beans规范,我觉得仅使用getter、setter和空构造函数会使代码更加繁琐,而且开发人员需要管理跟踪设置所有必需的实例。有人能给我一个使用这种设计的好案例吗?我无法感受它的用途。我能想到一个用途是:“当您需要创建一个类的实例,以便其数据成员将在代码的后续部分中确定时。”编辑:各位,我不是要发起一场讨论。不想讨论优缺点。我不想寻找当前像Spring等库强制使用Beans的例子。我正在寻找一个例子来理解Java Beans所带来的工程优势。“只需要一个Java Beans设计有帮助的例子”

我认为你需要(重新)学习面向对象编程概念。 - Raúl
6个回答

5

许多的库和规范(例如 JPA, JavaEL)使用 Java Beans 规范,并依赖于该行为。

使用 getters 和 setters 的优点是可以在这些方法内添加代码,例如创建“虚拟”属性,在运行时计算而不是存储在字段中。

此外,使用 getters 和 setters 允许其他框架包装这些方法并提供附加功能,例如更改日志等。在许多情况下,这是通过内部创建子类并覆盖 getters 和 setters 来完成的。用户不会注意到这点,因为这种“编织”或“代理”通常在运行时完成。例如,Hibernate 使用这种方式当调用 getter 访问相关集合或实体时提供延迟加载功能。

更新:

根据请求提供一个“虚拟”属性示例:

假设您有一个Person bean,它具有 firstNamelastName 字段。 你可以通过提供以下 getter 添加一个只读虚拟属性 name

public String getName() {
  return getFirstName() + " " + getLastName();
}

更新2:

关于为什么需要使用getter和setter的另一个说明:这基本上是由Java的工作方式决定的。像C#这样直接支持属性的语言,可以让您编写类似于person.firstName = "Joe";的代码,并且如果有setter,则仍然使用它,如果属性是只读的,则抛出错误。因此,如果您为firstName添加了setter,那些语言会在开发人员不必更改任何内容的情况下将firstName = "Joe"内部转换为setFirstName("Joe") - 这是一种相当优雅的解决方案。 :)

由于Java不支持这一点,即使它们没有特殊功能,我们也必须始终提供访问器方法(setter / getter)- 以防将来可能需要更改它们。


我知道这是Spring的要求,但我需要一个理由来了解这种设计的工程优势。 - Mangat Rai Modi
@MangatRaiModi 你有没有读完整个答案?我已经提到了一些原因 :) - Thomas
抱歉,我猜你在我写的时候编辑了答案。我赶快到这里了。 - Mangat Rai Modi
“虚拟”属性?我没听清楚那部分。但是你能否解释一下。谢谢 :) - Mangat Rai Modi
1
@MangatRaiModi 我加了一些更新,希望现在更清楚了。也请阅读第三段,因为我认为那是一个 Java Beans 设计可以帮助 的例子,正如你所说的那样。如果没有该设计,实现 JPA 惰性加载将会很困难。 - Thomas
我现在完全理解了。虚拟属性和延迟加载。谢谢! - Mangat Rai Modi

1
需要一个空构造函数,通过持久性框架的反射来创建新实例。如果您没有为类提供任何带参数的其他构造函数,则不需要提供空构造函数,因为您会默认获得一个。
根据我的经验,这是为了防止有人添加带参数的构造函数,从而有效地删除默认构造函数。通过显式实现默认构造函数,这种情况更不可能发生。
此外,我想你正在想象一个具有许多属性的类,只使用getter和setter将很难填充,但也请注意以下几点:
- getter将自动化视图部分。 - setter将允许您在必要时添加验证或错误控制。

这是一个有意义的案例。 - Mangat Rai Modi

1
除了JavaBeans规范实际的优缺点之外,我认为重要的是要记住,它是在1996年引入的一项规范,旨在实现对Java代码的可视化编辑。我不知道这种编程方法是否成功并被广泛采用(个人从未使用过它)。我知道的是,该规范继续存在并得到广泛应用(在某些情况下,我认为有时也用于不太适合的上下文中)。
我认为JavaBeans最有用的地方是一个框架。一个很好的例子是Spring。当类实例化不是由程序员负责而是委托给应用程序容器(例如通过反射)时,JavaBean类非常适合使用。

1

Getters和Setters确保了基本的面向对象概念 - 封装

想象一下,你编写了一个类的代码,另外十几个程序员从你的公司编写了使用你的类的程序。因此,任何人都可以更改您的实例变量,这可能会损害您的代码。

所以你应该:

保持实例变量受保护(使用访问修饰符,通常是private)。

创建公共访问器方法,并强制调用代码使用这些方法而不是直接访问实例变量

他们的代码引出了您代码中的错误。

看下面的例子。

public class MyClass{
public int size;
public int weight;
...
}
public class OthersClass {
public static void main (String [] args) {
MyClass myClass= new MyClass();
myClass.size = -5; // Legal but bad logic
}
}

所以基本上它通过指定一个setter来帮助验证。这很有道理,谢谢! - Mangat Rai Modi
这不是一种验证方式。这是我们期望使用强大的面向对象编程概念来编写逻辑的方式。因此,将不存在冲突或其他不良问题。 - Don Chakkappan

0

正如你上面描述的那样,JavaBeans 可以被用作 DAO(数据访问对象),用于检索和保存数据到(主要是 SQL)数据库。它们很有用,特别是在你真正关心的只有数据时。


请问您能否详细解释一下,为什么这种设计有助于将数据存储到/从SQL中? - Mangat Rai Modi

0

许多人会告诉你,Java Beans比充当“数据传输对象”的普通Java对象要好得多。

但是其他人,例如这位在他著名的书中https://cleansourcecode.files.wordpress.com/2013/10/clean-code.pdf的作者,建议大多数情况下,“bean”和getter和setter并没有太多附加价值(整个第6章都致力于探讨这个问题)。

因此,您应该自己决定(可能与团队成员一起),使用“Java Beans”还是“普通数据传输对象”更好地解决了您的问题。

当然,“beans”强制您使用setter,这使您可以稍后添加验证。另一方面:这种更改修改了您的方法的语义;突然间一个setter执行验证并开始抛出异常可能是完全错误的。因为,如果您更改了方法的契约,则可能不希望在幕后隐含地执行该操作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接