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; } } |
以上是代碼而不是所必須的.這意味著要變成返回一些值的一個輕便的方法,我們來做些改變:
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())); } |
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; } } |
public class Pair { public final A first; public final B second; public Pair(A first, B second) { this.first = first; this.second = second; } } |
public static Pair // find the person in the DB.... return new Pair(person.getName(), new Date(person.getDOB().getTime())); } 使用它: Pair System.out.println(personNameDOB.first); System.out.println(personNameDOB.second); |
· 你不想別人來擴展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); } } |
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的方法已經有508次圍觀