我正在使用JavaFX的模型实体属性witch允许我更改单个位置上的值,将它们绑定到UI并在模型实体数组中添加具有额外条件的更改侦听器(唯一值等)。JavaFX:基于属性的实体与基于属性的包装
我必须存储在数据库中的模型,所以这个问题是以下几点:
我应该改变我的模型实体到JPA实体(与AccessType.PROPERTY设定值)当我这样做没有必要需要所有值(或所有时间)作为属性或创建基于属性的包装器(面向)来访问它的基于经典值的实体类。
注意:某些可绑定属性根本不需要保留。
我正在使用JavaFX的模型实体属性witch允许我更改单个位置上的值,将它们绑定到UI并在模型实体数组中添加具有额外条件的更改侦听器(唯一值等)。JavaFX:基于属性的实体与基于属性的包装
我必须存储在数据库中的模型,所以这个问题是以下几点:
我应该改变我的模型实体到JPA实体(与AccessType.PROPERTY设定值)当我这样做没有必要需要所有值(或所有时间)作为属性或创建基于属性的包装器(面向)来访问它的基于经典值的实体类。
注意:某些可绑定属性根本不需要保留。
不管你是否应该使用特定的技术都是基于观点的,所以我不会在这里回答你确切的问题。我只会提供一些有利有弊的选项。
在您的JPA注释的实体类中直接使用JavaFX属性的优点是您可以保持设计的简单性,只需一个类代表每个实体,而不用围绕实体注释类的包装类。
直接在JPA实体类使用JavaFX性能的缺点是:
您可以通过使用“超级懒惰”模式来最小化使用JavFX属性的成本。这里属性对象只有在实际使用时才会被创建(例如,如果你注册了一个监听器);否则,使用相同的数据类型的代理领域:
@Entity
@Access(AccessType.PROPERTY)
public class Person {
private IntegerProperty age ;
private int _age ;
private StringProperty name ;
private String _name ;
private int id ;
@Id
public int getId() {
return id ;
}
public void setId(int id) {
this.id = id ;
}
public IntegerProperty ageProperty() {
if (age == null) {
age = new SimpleIntegerProperty(_age);
}
return age ;
}
public int getAge() {
if (age == null) {
return _age ;
} else {
return age.get();
}
}
public void setAge(int age) {
if (this.age == null) {
_age = age ;
} else {
this.age.set(age);
}
}
public StringProperty nameProperty() {
if (name == null) {
name = new SimpleStringProperty(_name);
}
return name ;
}
public String getName() {
if (name == null) {
return _name ;
} else {
return name.get();
}
}
public void setName(String name) {
if (this.name == null) {
_name = name ;
} else {
this.name.set(name);
}
}
}
这基本上避免了(几乎)任何性能开销由于非JavaFX的环境中使用这个类,因为属性不是实例化,除非通过明确要求xxxProperty()
方法。请注意,调用这些方法是注册侦听器的唯一方法,因此如果侦听器已注册,代码将保证通知这些侦听器是否随后调用setXxx(...)
。这里的代价是一些代码冗长,以及一些冗余空值检查的非常小的成本(无论如何JVM可能会进行优化)。
这种技术显然没有解决依赖于JavaFX API的问题。
另一个可能的选择是使用一个普通的JavaBean与属性变化监听器:
@Entity
public class Person {
@Id
private int id ;
private int age ;
private String name ;
private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
public int getAge() {
return age ;
}
public void setAge(int age) {
int oldAge = age ;
this.age = age ;
pcs.firePropertyChange("age", oldAge, age);
}
public String getName() {
return name ;
}
public void setName(String name) {
String oldName = name ;
this.name = name ;
pcs.firePropertyChange("name", oldName, name);
}
// ...
}
现在,在您的JavaFX的客户端,你可以做这样的事情:这里
TableView<Person> contactTable = new TableView<>();
TableColumn<Person, String> nameCol = new TableView<>("Name");
nameCol.setCellValueFactory(cellData -> {
try {
return JavaBeanStringPropertyBuilder.create()
.bean(cellData.getValue())
.name("name")
.build();
} catch (Exception exc) {
return new RuntimeException(exc);
}
});
的好处是,你的实体完全没有任何对JavaFX的依赖。成本是您的客户端代码更加冗长,并且缺少编译时检查是否存在正确的方法。这里有相当多的反思,所以在评估客户端代码中的属性时,你会遇到一些(可能是次要的)性能下降。有关详细信息,请参阅JavaBean wrapping with JavaFX Properties。
我想其他评论可能是相关的。您可能希望在JavaFX上下文中使用实体的最常见用例是,您既有Web应用程序又有独立的(JavaFX)客户端应用程序,它们都通过Web服务访问数据(例如提供和使用JSON)。在这种情况下,您可以考虑同时保留两组类,一组使用JavaFX属性,另一组使用Java bean实现。由于get/set
方法的集合是相同的,因此JSON序列化程序应该能够将相同的JSON表示形式转换为任一形式。你可以保持同步两种形式使用的接口:
public interface Person {
public int getAge() ;
public void setAge(int age) ;
public String getName() ;
public void setName(String name) ;
}
具有明显的实现
@Entity
public class PersonEntity implements Person {
private int age ;
private String name ;
@Id
private int id ;
// get/set methods omitted...
}
和
public class PersonFX implements Person {
private final StringProperty name = new SimpleStringProperty() ;
private final IntegerProperty age = new SimpleIntegerProperty() ;
public StringProperty nameProperty() {
return name ;
}
@Override
public final String getName() {
return nameProperty().get();
}
@Override
public final void setName(String name) {
nameProperty().set(name);
}
// similarly for age...
}
现在在JavaFX的客户端,你可以有一个JSON引擎,[德]将JSON序列化为PersonFX
实例,并且在服务器上有一个JSON引擎,它[de]序列化相同的来自PersonEntity
实例的JSON数据。由于JSON引擎会通过调用get/set方法来工作,所以对象本质上具有相同的形式。自从我开始使用JavaFX之后,我还没有对XML数据进行序列化,所以我不确定同样的方法是否适用于XML数据,但我认为您也可以完成这项工作。您甚至可以在Java序列化数据流中执行此操作,方法是在实现类中定义readObject
和writeObject
方法,这些方法需要相同形式的数据(或使用序列化代理)。
更多我想到它我总是回到某种包装(谢谢你的方式:http://stackoverflow.com/questions/23522130 :-)。应用程序不需要处理来自多个来源的数据(序列化)。实体将主要代表统计结果(在大多数情况下)。不过,我必须为这些数据创建一个手动工具来测量和插入。这可能会在功能上发生变化,可能会创建新的(更自动的)工具,或者可能会引入不同的测量方式。包装可以帮助我独立调整每个案例的外观。 – Wolfer
你能澄清你的问题吗?您在问是否使用JavaFX属性实现JPA实体的好设计,实体有时将用于JavaFX上下文(需要可观察属性),有时用于不同的上下文(不需要任何功能从属性)? –
其实这正是我所要求的。 – Wolfer