我正在使用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