设计模式 - Java Bean 的 setter 是否允许返回此内容?



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

:

ClassA setItem1() {
      return this;
}
ClassA setItem2() {
      return this;
}

然后我可以使用新的ClassA(). setitem1 (). setitem2 ()

关于JavaBeans规范有很多误解。

它存在的主要原因是统一的Java"组件"模型。这是一种使用反射与Java对象进行编程交互的方法。API本身被命名为JavaBeans Introspection。请看看示例用法,您将比一般的Java程序员了解更多。

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

所以,在我看来,混合流畅的api和JavaBeans规范是不可能的。这是两个完全不相关的概念,可能会相互干扰。当方法签名不同(返回类型)时,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对象派生的属性:

  • <
  • 名称/gh>大小

您可能想看看当您将void返回类型更改为其他类型时会发生什么。我这样做了,结果是一样的。那么,这意味着它是允许的吗?

恐怕不行。JavaBeans规范对这些方法签名非常严格。只是碰巧实现是宽容的。尽管如此,我还是不建议将流畅接口与JavaBeans混合使用。你不能真的相信,如果发现现在有效,它将来也会有效。

但是,从另一方面看,你似乎没有充分使用JavaBeans。只有getter/setter对方法。这取决于您如何实现和设计api。

JavaBean规范将JavaBean描述为:

Java Bean是一个可重用的软件可操作的组件可视化地在构建工具

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

使用JavaBeans规范(第7.1节和8.3节)的访问器方法调用普通旧Java对象的"JavaBean"是很常见的。事实是,这样的对象可能还远远不能满足所有的要求。

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

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教程。

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

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

使得(至少对我来说)这些方法的意图更清楚一些。

检查Oracle JavaBean页面后,我没有发现任何明确告诉您setter需要为空的内容。然而,所有的例子都有void set方法。

Java API中的PropertyDescriptor支持非void setter,所以我认为让你的setter返回this应该是相当安全的。为了安全起见,您应该检查一下您打算使用的框架是否使用了反射。例如,在3.1版本之前,Spring不支持xml配置中的非空setter。

我猜这没有违反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"的setter不受返回类型的影响(返回类型不用于通过反射定位方法)。这也是有道理的,因为除了返回类型不同之外,在一个作用域中不可能有两个完全相同的方法。

只是补充一下,对于使用Spring 3.1+的人来说,这不再是一个问题了

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

是。这是一种比较常见的技术,叫做方法链接,可以用来创建一个"流畅的接口"。

参见:http://en.wikipedia.org/wiki/Method_chaining, http://en.wikipedia.org/wiki/Fluent_interface

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

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

没有什么可以阻止你在接口中提供返回目标对象的setter方法…

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

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

中的Builder Pattern中查看Stack Overflow。

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

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

最新更新