11

我讨厌 JavaBeans 模式,我的热情就像一千个太阳的火焰一样燃烧。为什么?

  • 详细。现在是 2009 年。我不应该为房产写 7 LOC。如果他们有事件监听器,那么请抓住你的帽子。
  • 没有类型安全的引用。没有类型安全的方式来引用属性。Java 的全部意义在于它是类型安全的,它最流行的模式根本不是类型安全的。

我想要的是这样的:

class Customer {
    public Property<String> name = new Property();
}

我主要是 Web 开发人员,所以它需要 JPA 和 Wicket 支持。

帮我下javabean火车!

4

11 回答 11

10

我认为您与那里的声明非常接近(请参见下面的草图)。但是,通过使用非 bean 方法,您可能会失去大多数假定 JavaBeans 协议有效的工具所提供的支持。请善待。下面的代码不在我的脑海中......

public class Property<T> {
    public final String name;
    T value;
    private final PropertyChangeSupport support;

    public static <T> Property<T> newInstance(String name, T value, 
                                              PropertyChangeSupport support) {
        return new Property<T>(name, value, support);
    }

    public static <T> Property<T> newInstance(String name, T value) {
        return newInstance(name, value, null);
    }

    public Property(String name, T value, PropertyChangeSupport support) {
        this.name = name;
        this.value = value;
        this.support = support;
    }

    public T getValue() { return value; }

    public void setValue(T value) {
        T old = this.value;
        this.value = value;
        if(support != null)
            support.firePropertyChange(name, old, this.value);
    }

    public String toString() { return value.toString(); }
}

然后继续使用它:

public class Customer {
    private final PropertyChangeSupport support = new PropertyChangeSupport();

    public final Property<String> name = Property.newInstance("name", "", support);
    public final Property<Integer> age = Property.newInstance("age", 0, support);

    ... declare add/remove listenener ...
}


Customer c = new Customer();
c.name.setValue("Hyrum");
c.age.setValue(49);
System.out.println("%s : %s", c.name, c.age);

因此,现在声明一个属性是一行代码,并且包括属性更改支持。我调用了 setValue() 和 getValue() 方法,所以它看起来仍然像一个 bean 来编写 Rhino 之类的代码,但为了简洁起见,您可以只添加 get() 和 set()。其余的留给读者练习:

  • 正确处理序列化
  • 处理空值检查
  • 如果您关心自动装箱开销,可能会为原子类型添加专业化。
  • ?? 我敢肯定还有更多的陷阱

另请注意,您可以子类化(通常作为匿名类)并覆盖 setValue() 以提供额外的参数检查。

我认为您无法真正摆脱“字符串引用”,因为这几乎就是反射的全部内容。

可悲的是,在这个时代,这仍然有点像汇编编程......如果你有选择的话,Groovy、C# 等可能仍然是更好的选择。

于 2009-01-14T01:43:30.110 回答
5

在以下位置查看我的 Bean 注释

http://code.google.com/p/javadude/wiki/Annotations

基本上你会做这样的事情:

@Bean(
  properties={
    @Property(name="name"),
    @Property(name="phone", bound=true),
    @Property(name="friend", type=Person.class, kind=PropertyKind.LIST)
  }
)
public class Person extends PersonGen {}

而不是自己定义所有这些额外的 get/set 等方法。

还有其他属性可以定义equals/hashCode、observers、delegate、mixins等。

它是一组注解和一个注解处理器,可以在 eclipse 或命令行构建中运行(例如在 ant 中)。处理器生成一个超类来包含所有生成的代码(注释处理器不能更改包含注释的类,顺便说一句)

于 2009-01-14T22:20:05.137 回答
3

您可能想查看Groovy - 一种动态类型、基于 JVM(并且完全兼容 Java)的语言,具有“真实”属性。

于 2009-01-13T23:12:50.633 回答
1

对于网络,我建议使用JSON(JavaScript Object Notation),

一种轻量级的数据交换格式

. 这是对 JSON?Bean转换器的引用。

于 2009-01-14T00:06:08.623 回答
1

使用 Spring 框架。它的目的是通过抽象您抱怨的大量基础工作来简化 Java 开发。

您可以将它与 Hibernate 一起使用,这将为您简化与数据源的交互。

有用的网站:

www.springsource.org/download

www.hibernate.org/

于 2009-01-14T12:58:32.417 回答
1

当我第一次使用 C# 时,我喜欢这些属性,但现在,在 VS 2008 中使用它们一段时间后,我不得不说我更喜欢 set-/get-methods。

重点是我个人的工作方式。当我有一个新类并且我想知道我可以用它做什么时,我只需键入 classname.set,Eclipse 就会向我显示我可以更改哪些“属性”。get 也是一样。也许它只是糟糕的 VS 方式,但是我必须浏览一长串这个 itelisense (所有东西都是混合的,而不是先显示属性),只是为了在我编译后发现我想要设置的属性是只读的。 ..doh!

是的,在 Java 中您需要很多行,但我只是编写属性并告诉 IDE“请为我创建 getter 和 setter”。但是这些方法往往会占用大量空间,这就是为什么我希望在 Java 中也有可以在 IDE 中折叠的区域。

于 2009-07-27T13:35:42.193 回答
0

您还可以构建一个代码生成器,从您编写的 DSL 创建您的 .java 类。您可以使用某种标记来描述您的类的名称、您想要的属性以及它们的类型。然后,使用生成 javabean 的程序处理该文件。或者您可以使用注释,并使用 ASM 之类的东西对类文件进行后处理,以注入访问器和修改器。我也相信 Spring 提供了其中一些功能,但我没有使用过它们。

于 2009-01-13T23:15:46.540 回答
0

试试JBoss 的SEAM框架,你应该会喜欢的。

于 2009-01-14T07:50:30.870 回答
0

一旦我尝试了这个:

interface IListenable {
    void addPropertyChangeListener( PropertyChangeListener listener );
    void removePropertyChangeListener( PropertyChangeListener listener );
}

abstract class MyBean extends IListenable {
    public abstract void setName(String name);
    public abstract String getName();

    // more things
}

public class JavaBeanFactory {

   public <T> Class<T> generate(Class<T> clazz) {
      // I used here CGLIB to generate dynamically a class that implements the methods:
      // getters
      // setters
      // addPropertyChangeListener
      // removePropertyChangeListener
   }
}

我用它作为这个(这只是一个例子):

public class Foo {
    @Inject
    public Provider<MyBean> myBeanProvider;

    public MyBean createHook(MyBean a) {
        final MyBean b  = myBeanProvider.get();
        a.addPropertyChangeListener(new PropertyChangeListener() {
             public void propertyChange(PropertyChangeEvent evt) {
                 b.setName((String) evt.getNewValue());
             }
        });
        return b;
    }
}
于 2009-01-14T12:39:56.930 回答
0

我在模型实体(使用 JPA 注释)上大量使用 JavaBean 属性,以便能够将它们数据绑定到 UI(使用 JFace)。

不幸的是,我没有第二个问题的解决方案(也许除了定义包含属性名称的常量)。

我生成侦听器样板的方法是让我的模型实体从使用反射处理它的 AbstractJavaBean 超类扩展。然后我可以使用创建 getter/setter 的默认方式,除了 setter 需要重写如下:

public void setRemarks(String remarks) {
    set("remarks", remarks);
}

AbstractJavaBean.set 然后使用反射(通过 Apache commons beanutils)通过其 getter 读取属性“remarks”的旧值,将新值设置为名为“remarks”的字段,并使用旧值和新值触发属性更改事件. 事实上,这个想法可以扩展为使依赖的“派生”属性能够在属性之一基于更改时自动触发属性更改,例如在属性“birthDate”更改时更改“age”。所有这些逻辑都可以在 AbstractJavaBean 内的一个地方编码,并由任何模型对象使用。

于 2013-05-02T13:10:02.987 回答
0

我正在寻找同样的东西,我真的很惊讶我找不到合适的图书馆。由于我经常感到疼痛,因此我在 2 年前开始了一个解决这些问题的小项目:正确地

可在以下网址获得: https ://github.com/aditosoftware/propertly 。我们现在在我们的产品中使用它。

它提供了带有泛型的静态类型、不同级别的侦听器、树导航、动态模型等等。主要优点是模型的描述是静态完成的,因此信息始终可用,并且在设计时考虑了可扩展性。因此,您可以使用自己的注释进行验证或定义数据从哪里读取和存储到哪里。

使用示例:

一个简单的 IPropertyPitProvider。属性是名字、姓氏和年龄。

// Generics describe parent, self and children
public class StudentPropertyPitProvider 
    extends AbstractPPP<IPropertyPitProvider, StudentPropertyPitProvider, Object>
{
  // IPropertyDescription gives static access to an IProperty's meta data like name and type.
  public static final IPropertyDescription<StudentPropertyPitProvider, String> FIRST_NAME =
      PD.create(StudentPropertyPitProvider.class);

  public static final IPropertyDescription<StudentPropertyPitProvider, String> LAST_NAME =
      PD.create(StudentPropertyPitProvider.class);

  public static final IPropertyDescription<StudentPropertyPitProvider, Integer> AGE =
      PD.create(StudentPropertyPitProvider.class);


  // Getters and setters can of course still be used for easier access. 
  public String getFirstName()
  {
    // getValue and setValue is available at AbstractPPP. That class is used for easier access. 
    // Propertly can be used without inheriting from that class, too.
    return getValue(FIRST_NAME);
  }

  public void setFirstName(String pFirstName)
  {
    setValue(FIRST_NAME, pFirstName);
  }

  public String getLastName()
  {
    return getValue(LAST_NAME);
  }

  public void setLastName(String pLastName)
  {
    setValue(LAST_NAME, pLastName);
  }

  public Integer getAge()
  {
    return getValue(AGE);
  }

  public void setAge(Integer pAge)
  {
    setValue(AGE, pAge);
  }

}

使用定义的提供者:

public class Sample
{

  public static void main(String[] args)
  {
    // Hierarchy is necessary to initialize the IPropertyPitProviders and for advanced features.
    Hierarchy<StudentPropertyPitProvider> hierarchy =
        new Hierarchy<>("student1", new StudentPropertyPitProvider());
    // The created student can be accessed from the hierarchy.
    StudentPropertyPitProvider student = hierarchy.getValue();
    // Listeners can be added.
    student.addPropertyEventListener(new PropertyPitEventAdapter()
    {
      @Override
      public void propertyChanged(IProperty pProperty, Object pOldValue, Object pNewValue)
      {
        System.out.println(pProperty.getName() + "=" + pNewValue);
      }
    });

    // The following calls will cause
    //  FIRST_NAME=Nils
    //  LAST_NAME=Holgersson
    //  AGE=32
    // to be printed on console through the listener.
    student.setFirstName("Nils");
    student.setLastName("Holgersson");
    student.setAge(32);
  }

}
于 2014-12-23T16:22:00.243 回答