歡迎您光臨本站 註冊首頁

應用技巧:提高Java Beans的方法

←手機掃碼閱讀     火星人 @ 2014-03-10 , reply:0

  Java類的選擇是真的只用一個typesafe解決方案,而其通過改進風格,這些類可以更好的代替structs,而且有他們自己的一些優勢.

  舉個帶有兩個arguments的一個返回類——一個name和一個 date of birth:

  

public class PersonNameDOB {

  private String name;

  private Date dob;

  public Date getDob() {

  return dob;

  }

  public void setDob(Date dob) {

  this.dob = dob;

  }

  public String getName() {

  return name;

  }

  public void setName(String name) {

  this.name = name;

  }

  }

  顯然這是一個編造的例子,有機會你可以有一個已經定義的可返回的Person 類.用一個方法返回兩個不同的對象,但是不要有已經為他們定義的一個類,或者也許你最終返回到一個類,這個類帶有更多的信息為了只從中得到一對條目.根據不同的可能更糟糕的情況.例如,如果有人調用你的方法開始在返回的對象中使用或是修改值時你會打算讓這樣的事情發生?

  以上是代碼而不是所必須的.這意味著要變成返回一些值的一個輕便的方法,我們來做些改變:

  

public class PersonNameDOB {

  public final String name;

  public final Date dob;

  public PersonNameDOB(String name, Date dob) {

  this.name = name;

  this.dob = dob;

  }

  }

  結果很短,但更適合這個任務.值被返回,setters也沒有必要了,我們只要在返回對象被創建時建立值就行了.它們不需要改變,它們在一個constructor中,他們會被製造出來的.現在他們是最終的結果,類公開也沒有任何風險,他們沒有受到影響,現在你可以擺脫getters和setter了.結果很短而且便於使用:

  

PersonNameDOB personNameDOB = SSNLookup.lookupBySSN("123-45-6789");

  System.out.println(personNameDOB.name);

  System.out.println(personNameDOB.dob);

  And the lookupBySSN method: lookupBySSN方法:

  public PersonNameDOB lookupBySSN(String ssn) {

  ... Find the person record in the DB, etc. ...

  return new PersonNameDOB(person.getName(), person.getDOB());

  }

  如果這個顯然看起來非常棒,只要忍受我把事情進一步發展.

  我喜歡這個方法來減輕返回對象.它是typesafe,沒有必要在返回後分配數組外的對象.更好的是,修改的屬性意味著這些返回的對象不能濫用——它們只是用於數據的轉移.

  將這個安全的步驟進一步,我建議你可以複製對象或是有可能使用不改變的對象,不這樣做通過調用方法會增加在你的donor對象的值的意想不到的修改.在我們的例子中,String是不可改變的,但是數據是複製的:

  

public PersonNameDOB lookupBySSN(String ssn) {

  ... Find the person record in the DB, etc. ...

  return new PersonNameDOB(person.getName(), new Date(person.getDOB().getTime()));

  }

  這個將阻止一個caller,操作如下:

  PersonNameDOB personNameDOB = SSNLookup.lookupBySSN("123-45-6789");

  personNameDOB.dob.setTime(0);

  從一方影響原始DOB值,這是個很大的風險.如果你不能使用這些不改變的值,要務必在你的結果中複製並返回那些副本.

  以上的模式是一個使用過多次的作為一個struct代替Java API調用,但是對創建這些類它仍然是一個損耗,如果你想要做的是返回兩個類型對象,這確實是很平常的(許多finder演算法可以更有效率的工作,通過簡單的返回相關的一對代替一個,如一個密碼,是添加到地圖中的有價值的pair).

  這種情況下這似乎像是一個低掛的水果,但是從Java SE標準分配中神秘失蹤的是一個genericized Pair class.看一看你如何能夠從上面的模式中構建它.

  ,值要比name和dob要普遍.最普遍的似乎是把fields命名為first和 second:

  

public class Pair {

  public final String first;

  public final Date second;

  public Pair(String first, Date second) {

  this.first = first;

  this.second = second;

  }

  }

  到目前為止一起都很順利.你現在有一個大致的類來返回Strings 和Dates,但不是其他的類型.如下:

  

public class Pair {

  public final A first;

  public final B second;

  public Pair(A first, B second) {

  this.first = first;

  this.second = second;

  }

  }

  不必去擔心通配符這些東西只是代碼一但返回類型的一個快捷方式.這個類現在可用於general type pairs,例如:

  

public static Pair lookupBySSN(String ssn) {

  // find the person in the DB....

  return new Pair(person.getName(), new Date(person.getDOB().getTime()));

  }

  使用它:

  Pair personNameDOB = SSNLookup.lookupBySSN("123-45-6789");

  System.out.println(personNameDOB.first);

  System.out.println(personNameDOB.second);

  你用的Pair 類還沒有結束.如果這個事情真的具有普遍性,你需要考慮一些事情:

  · 你不想別人來擴展Pair class並改變它所做的事情——有肯能打破的類的原本意圖.

  · new Pair()可以,但是它看上去有點笨拙.你可以做到比它還要好.

  · Pair對返回的值很有用,但是作用很小,例如,作為地圖中的答案.

  · 有一個很好的形式的Pair字元串代表是相當不錯的可以進行調試或是其他toString()使用.

  · ,也許(這是有爭議的),讓Pair和包含的對象序列化如果內容也序列化那將是非常好的.

  ,讓我們看一下pair執行時如何變化的:

  

public final class Pair implements Serializable {

  private static final long serialVersionUID = 1L; // shouldn't

  // need to change

  public final A first;

  public final B second;

  private Pair (A first, B second) {

  this.first = first;

  this.second = second;

  }

  public static Pair of (A first, B second) {

  return new Pair(first,second);

  }

  @Override

  public boolean equals(Object obj) {

  if (obj == null) {

  return false;

  }

  if (getClass() != obj.getClass()) {

  return false;

  }

  final Pair other = (Pair) obj;

  if (this.first != other.first &&

  (this.first == null || !this.first.equals(other.first))) {

  return false;

  }

  if (this.second != other.second &&

  (this.second == null || !this.second.equals(other.second))) {

  return false;

  }

  return true;

  }

  @Override

  public int hashCode() {

  int hash = 7;

  hash = 37 * hash (this.first != null ?

  this.first.hashCode() : 0);

  hash = 37 * hash (this.second != null ? this.second.hashCode() : 0);

  return hash;

  }

  @Override

  public String toString () {

  return String.format("Pair[%s,%s]", first,second);

  }

  }

  你應該讓constructor很秘密的,但是提供一個靜態的of()方法,我想讀起來會更好:

  return Pair.of(person.getName(), new Date(person.getDOB().getTime()));

  你把Pair類放,沒人會不理它並且改變類的原本意圖.這看起來很嚴格,但是為了更廣泛使用的目的,防範這樣的事情是十分明智的.如果有人像讓Pair做不同的工作,他們需要寫入自己的執行,向同行證明它是有道理的.

  equals()和hashCode()方法說明這個類能夠用於更多的目的而不僅僅是返回值.他們可用於,例如,作為地圖的關鍵點.這有一個建議,是對使用這個樣式的任何類型的返回對象,是讓你的IDE為你創建equals和hashCode方法——這些是簡單的實現但是這裡有要記住的一些事情是關於hashCode 和equals的合同,例如,null checks和不同的types(參見在Josh Bloch的Effective Java 2nd ed書中關於明確的描述).IDEs往往有插入最好的已定義的練習樣板,我只用NetBeans來創建這些.也許它們可以再精簡一點,但是這些執行是很安全的.我從NetBeans equals()執行中刪除通用簽名,它沒有必要了而且會製造疑惑.

  toString()覆蓋了剛剛列印的一個漂亮格式的pair,像"Pair[Fred Jones,Sun Mar 22 12:55:44 PDT 2009]".這個特別用於調試的popups.

  現在類完成序列化.我相信這點是選擇變得更不可相信的一點,但是collection序列化,在我看來Pair也應該序列化.如果類在沒有序列化的Pair中使用,Pair就不是阻止序列在類中使用的東西了.


[火星人 ] 應用技巧:提高Java Beans的方法已經有507次圍觀

http://coctec.com/docs/java/show-post-62084.html