Java bean的setter许可是否会返回?

时间:2011-04-21 08:17:31

标签: java design-patterns

我可以定义setter方法来返回它而不是void吗?

像:

ClassA setItem1() {
      return this;
}

ClassA setItem2() {
      return this;
}

然后我可以使用新的ClassA()。setItem1()。setItem2()

10 个答案:

答案 0 :(得分:13)

对JavaBeans规范存在很多误解。

它存在的主要原因是统一的Java“组件”模型。这是一种使用Reflection以编程方式与Java对象进行交互的方法。 API本身名为JavaBeans Introspection。请看一下示例用法,你会比普通的Java程序员知道更多。

Introspection API可用于以统一的方式操作GUI元素。您的组件将其属性公开为一对getter和setter,以便可以在GUI构建器的属性表上在运行时发现和操作它们。

因此,在我看来,混合流畅的API和JavaBeans Spec是不行的。这是两个完全不相关的概念,可能会相互破坏。当方法签名不同(返回类型)时,JavaBeans内省可能不起作用。

看看这个例子(摘自链接教程):

public class SimpleBean
{
private final String name = "SimpleBean";
private int size;

public String getName()
{
    return this.name;
}

public int getSize()
{
    return this.size;
}

public void setSize( int size )
{
    this.size = size;
}

public static void main( String[] args )
        throws IntrospectionException
{
    BeanInfo info = Introspector.getBeanInfo( SimpleBean.class );
    for ( PropertyDescriptor pd : info.getPropertyDescriptors() )
        System.out.println( pd.getName() );
}
}

此示例创建一个非可视bean并显示从BeanInfo对象派生的以下属性:

  • 名称
  • 尺寸

您可能希望了解将void返回类型更改为其他内容时会发生什么。我这样做了,结果是一样的。那么,这是否意味着它被允许?

我害怕不。 JavaBeans规范对这些方法签名非常严格。事实上,实施是宽容的。尽管如此,我还是不喜欢将流畅的界面与JavaBeans混合在一起。你不能真正依赖它,如果这个发现现在有效,那么将来也会如此。

但是,从另一方面来看 - 看起来你并没有完全使用JavaBeans。只有getters / setters对方法。取决于您如何实施和设计您的API。

答案 1 :(得分:13)

JavaBeans Specification将JavaBean描述为:

  

Java Bean是一种可重用的软件   可以操纵的组件   在构建器工具中可视化

他们需要在其他属性中提供内省,自定义,事件和持久性(第2.1节:什么是bean?)

通常使用JavaBeans规范(第7.1和8.3节)之后的访问器方法将“Java Bean”调用普通旧Java对象。事实是,这样的对象仍然远远不能满足所有要求。

如果您在此类中定义的对象实际上是JavaBean,那么您的方法必须根据JavaBean规范第7.1节返回void,其中访问器方法描述如下:

void setFoo(PropertyType value); // simple setter
PropertyType getFoo(); // simple getter

8.3节命名设计的属性模式说:

默认情况下,我们使用设计模式通过查找表单的方法来定位属性:

public <PropertyType> get<PropertyName>();
public void set<PropertyName>(<PropertyType> a);

此外,对于布尔属性,我们允许getter方法匹配模式:

public boolean is<PropertyName>();

但是,如果您的类只是一个POJO,那么使用方法链策略没有任何问题,因为您实际上是在构建JavaBean,因此可以偏离规范。并非你定义的所有类都应该是JavaBeans,对吗?

您可能希望查看Oracle JavaBeans Tutorial

答案 2 :(得分:7)

没理由你不能这样做。就个人而言,如果在对象创建过程中使用了setter,我会将它们命名为Item1()和withItem2()。

ClassA obj = new ClassA().withItem1(item1).withItem2(item2);

让我更清楚一点(对我来说)这些方法的意图是什么。

答案 3 :(得分:5)

检查Oracle JavaBean pages后,我没有找到任何明确告诉你setter需要无效的内容。然而,所有示例都有空集方法。

Java API中的PropertyDescriptor支持非void setter,所以我认为让你的setter返回它应该是非常安全的。为了安全起见,您应该查看您打算使用反射的框架。例如,没有Spring support non-void setters in xml config prior to version 3.1

答案 4 :(得分:3)

我猜这不违反JavaBean规范,虽然我不确定。

查看以下示例:

public class JavaBean {

    private String value;

    public String getValue() {
        return value;
    }

    public JavaBean setValue(String value) {
        this.value = value;
        return this;
    }

    public static void main(String[] args) throws Exception {
        JavaBean bean = new JavaBean();
        JavaBean.class.getMethod("setValue", String.class).invoke(bean, "test");
        System.out.println(bean.getValue());
    }
}

许多框架使用反射API访问JavaBeans。如上所示,访问返回'this'的清除程序不受返回类型的影响(返回类型不用于通过反射定位方法)。这也是有道理的,因为除了返回类型之外,在一个范围内不能有两个相同的方法。

答案 5 :(得分:1)

是。这是一种称为Method Chaining的常见技术,可用于创建“流畅的界面”。

请参阅:http://en.wikipedia.org/wiki/Method_chaininghttp://en.wikipedia.org/wiki/Fluent_interface

答案 6 :(得分:1)

绝对没有什么可以阻止你这样做,但为什么。如果你想这样做,请创建一个带有args的构造函数。请记住,一些使用bean的软件不会期望返回值,并且可能会产生一些意想不到的结果

如果您只是想简化初始化,(可能要设置测试),您可以使用一些groovy代码。

答案 7 :(得分:1)

只是为使用Spring 3.1+的人添加它,这不再是一个问题

http://static.springsource.org/spring/docs/3.1.0.M2/spring-framework-reference/html/new-in-3.1.html

答案 8 :(得分:0)

没有什么能阻止你提供setter方法,它们将目标对象作为接口中的约定返回...

但是,您还必须使用Java Bean Simple Property setter方法的规范签名(例如void setProp(Type t)),否则bean属性将无法被其他期望的软件识别为可写入签名。

答案 9 :(得分:0)

Builder模式通常用于构造不可变对象。尽管JavaBeans本质上不是不可变的,但我经常在我的JavaBeans上使用构建器模式,因为它提供了一个流畅的接口,我可以在我的测试中使用它。这两者在不破坏JavaBean规范的情况下很容易相互兼容。您可以在Builder Pattern in Effective Java

上的Stack Overflow上查看它

您只需要确保包含默认构造函数以及私有Builder构造函数,然后将标准getter和setter放在JavaBean对象中。

这比构造函数链更清晰,也更容易阅读。