在模型类中使用 javafx.beans 属性 [英] Using javafx.beans properties in model classes

查看:34
本文介绍了在模型类中使用 javafx.beans 属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在模型类中使用 JavaFX bean 属性是否正确?

Is it a correct practice to use JavaFX beans properties in the model classes?

我想知道在模型类中使用属​​性以便能够更轻松地将它们与视图组件绑定是否是一个好习惯.我不担心将来这些库的可用性,因为我的程序将在 JRE8 或更高版本上运行,但在模型类中使用 JavaFX 库的性质让我持怀疑态度,我特别担心当前和未来的不兼容,因为我想使用 Hibernate 来持久化这些属性.

I wonder if it is a good practice to use properties in model classes to be able to bind them easier with the view components. I'm not worried about the availability of those libraries in future because my program will be run on JRE8 or later but the nature of using the JavaFX libraries in the model classes make me skeptical and I'm worried about current and future incompabilities specially because I want to use Hibernate to persist those attributes.

注意:我使用纯 JavaFX 环境,我的应用程序中永远不需要 Swing 兼容性.

Note: I use a pure JavaFX environment and I will never need Swing compability in my application.

推荐答案

我将在这里提出一些不同意见.

I'm going to offer something of a dissenting opinion here.

JavaFX 属性和 JPA

正如我对 Jewelsea 的回答所评论的那样,只要您使用属性访问"而不是字段访问",就可以将基于 JavaFX 属性的 bean 与 JPA 结合使用.我链接的 博客文章更详细地说明这一点,但基本思想是任何注释都应该在 get...() 方法上,而不是在字段上.据我所知,这确实阻止了将任何只读 JavaFX 属性模式与 JPA 结合使用,但我从来没有真正觉得 JPA 与只读属性(即 get 方法和无 set 方法)配合得很好.

As I commented on jewelsea's answer, using a JavaFX property-based bean with JPA is possible as long as you use "property access" rather than "field access". The blog post I linked there goes into more detail on this, but the basic idea is that any annotations should be on the get...() methods and not on the fields. As far as I can see, this does prevent use of any of the read-only JavaFX property patterns in conjunction with JPA, but I've never really felt JPA played well with read only properties (i.e. get methods and no set method) anyway.

序列化

与我对jewelsea的回答的评论相反,并且有几周的时间来处理这个问题(并且已经被安置在我面临使用JavaFX属性在JavaFX客户端复制几个实体类的位置),我认为可以解决 JavaFX 属性缺乏序列化的问题.关键的观察是你真的只需要序列化属性的包装状态(而不是,例如,任何侦听器).您可以通过实现 java.io.Externalizable 来做到这一点.ExternalizableSerializable 的子接口,需要你填写 readExternal(...)writeExternal(...) 方法.可以实现这些方法以仅外部化由属性包装的状态,而不是属性本身.这意味着,如果您的实体被序列化然后反序列化,您将最终获得一个新的属性实例,并且不会保留任何侦听器(即侦听器实际上变成 transient),但就我而言可以看出这在任何合理的用例中都是需要的.

Contrary to my comment on jewelsea's answer, and with the benefit of a few weeks to work with this (and having been placed in a position where I was facing replicating several entity classes on a JavaFX client side using JavaFX properties), I think the lack of serialization of JavaFX properties can be worked around. The key observation is that you really only need to serialize the wrapped state of the property (not, for example, any listeners). You can do this by implementing java.io.Externalizable. Externalizable is a sub-interface of Serializable that requires you to fill in the readExternal(...) and writeExternal(...) methods. These methods can be implemented to externalize just the state wrapped by the property, rather than the property itself. This means that if your entity is serialized and then deserialized, you will end up with a new property instance, and any listeners will not be preserved (i.e. the listeners effectively become transient), but as far as I can see this would be what was wanted in any reasonable use case.

我试验了以这种方式定义的 bean,一切似乎都运行良好.此外,我还进行了一个小实验,在客户端和 Restful Web 服务之间传输它们,使用 Jackson 映射器在 JSON 表示之间进行转换.由于映射器仅依赖于使用 get 和 set 方法,因此效果很好.

I experimented with beans defined this way and it all seems to work nicely. Additionally, I ran a small experiment in transferring them between the client and a restful web service, using the Jackson mapper to convert to and from a JSON representation. Since the mapper just relies on using the get and set methods, this works just fine.

一些注意事项

需要注意几点.与任何序列化一样,拥有无参数构造函数很重要.当然,JavaFX 属性包装的所有值本身都必须是可序列化的——这与任何可序列化 bean 的规则相同.

A couple of points need to be observed. As with any Serialization, it's important to have a no-argument constructor. And of course, all values wrapped by the JavaFX properties must themselves be serializable - again this is the same rule as for any serializable bean.

JavaFX 属性通过副作用工作的观点得到了很好的理解,在将这些属性(在某种程度上,考虑到单线程模型设计)移动到潜在的多线程模型时需要小心谨慎.线程服务器.一个好的经验法则可能是,如果您使用此策略,则侦听器应仅在客户端注册(请记住,这些侦听器在传输回服务器时是暂时的,无论是通过序列化还是通过 JSON 表示).当然,这表明在服务器端使用这些可能是一个糟糕的设计;它变成了拥有所有人的一切"的单个实体的便利性(JavaFX 客户端的可观察属性,可序列化用于持久性和/或远程访问,以及具有用于 JPA 的持久映射)与公开功能之间的权衡(例如可观察性)它可能不完全合适(在服务器上).

The point about JavaFX properties working via side-effects is well taken, and care needs to be exercised when moving these properties (which are, to some extent, designed with a single-threaded model in mind) to a potentially multi-threaded server. A good rule of thumb is probably that if you use this strategy, listeners should only be registered on the client side (and remember, those listeners are transient with respect to transfer back to the server, whether by serialization or by JSON representation). Of course, that suggests that using these on the server side then might be a bad design; it becomes a trade-off between the convenience of having a single entity that is "all things to all people" (observable properties for the JavaFX client, serializable for persistence and/or remote access, and with persistent mappings for JPA) versus exposing functionality (e.g. observability) where it might not be fully appropriate (on the server).

最后,如果您确实使用了 JPA 注释,那些注释具有运行时保留,这意味着(我认为)您的 JavaFX 客户端将需要类路径上的 javax.persistence 规范.

Finally, if you do use the JPA annotations, those have runtime retention which implies (I think) that your JavaFX client will need the a javax.persistence specification on the classpath).

以下是此类四季皆宜"实体的示例:

Here's an example of such a "man for all seasons" entity:

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.time.MonthDay;

import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

/**
 * Entity implementation class for Entity: Person
 *
 */
@Entity

public class Person implements Externalizable {


    private static final long serialVersionUID = 1L;

    public Person() {

    }

    public Person(String name, MonthDay birthday) {
        setName(name);
        setBirthday(birthday);
    }

    private final IntegerProperty id = new SimpleIntegerProperty(this, "id");

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    public int getId() {
        return id.get();
    }

    public void setId(int id) {
        this.id.set(id);
    }

    public IntegerProperty idProperty() {
        return id ;
    }

    private final StringProperty name = new SimpleStringProperty(this, "name");

    // redundant, but here to indicate that annotations must be on the property accessors:
    @Column(name="name")
    public final String getName() {
        return name.get();
    }

    public final void setName(String name) {
        this.name.set(name);
    }

    public StringProperty nameProperty() {
        return name ;
    }

    private final ObjectProperty<MonthDay> birthday = new SimpleObjectProperty<>();

    public final MonthDay getBirthday() {
        return birthday.get();
    }

    public final void setBirthday(MonthDay birthday) {
        this.birthday.set(birthday);
    }

    public ObjectProperty<MonthDay> birthdayProperty() {
        return birthday ;
    }

    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeInt(getId());
        out.writeObject(getName());
        out.writeObject(getBirthday());
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException,
            ClassNotFoundException {
        setId(in.readInt());
        setName((String) in.readObject());
        setBirthday((MonthDay) in.readObject());
    }

}

这篇关于在模型类中使用 javafx.beans 属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆