[英]A method declaring a mutable data structure as an output and returning an immutable one actually
最近,我就這個問題進行了激烈的討論。
讓我們說我用Java創建了這個方法:
public Set<String> getRich() {
return ImmutableSet<String> ....;
}
每當我在拉動請求中看到它時,我會大喊並嘗試解釋它為什么是錯誤的。 通過這樣做,我通過承諾他們將得到一個Set來誤導我的方法的消費者。 這意味着他們可以刪除或添加元素。 javac很樂意編譯它,但會拋出RuntimeException 。 除此之外 ,它違反了“利斯科夫替代原則” 。
就個人而言,我總是這樣做:
public ImmutableSet<String> getRich() {
return ImmutableSet<String> ....;
}
這樣,沒有人會在腳下射擊自己。
一種建議的方法是返回Iterable 。 我認為這很糟糕,因為該方法的使用者將失去HashSet,HashMap或其他任何東西(通過無法調用set.get(hash))的潛在能力。
另一種方法是 - 作為消費者 - 創建getRich()方法輸出的副本。 但是你如何確定消費者會這樣做呢?
當然,你有那些堅持OOP設計原則的人說:“總是編程接口”。 對我來說 - 在這種特殊情況下 - 這是有史以來最糟糕的選擇。
你會如何處理這個案子?
(非主題:這個案例是一個完美的例子,靜態類型如何確保正確性,但永遠不會確保正確性)。
從技術上講 ,將返回類型聲明為Set<T>
並不違反LSP。
Set<T>.Add
的文檔明確聲明實現可能會拋出UnsupportedOperationException
。 這意味着客戶有責任檢查該集合是否可變。
現在,是否使ImmutableSet<T>
擴展Set<T>
是一個不錯的選擇,這是有爭議的。 我個人認為這是一個非常糟糕的選擇 - 客戶端代碼不應該充斥着try / catches來查明一個集合是否可變。 此外, Set<T>
甚至不提供isMutable()
方法讓客戶端輕松執行檢查! 為不可變集合設置單獨的接口將是一個更清潔的設計。
我個人會解決這個設計缺陷 ,正如你的建議,將返回類型聲明為ImmutableSet<T>
。
問題的第二部分是你是否應該返回ImmutableSet<T>
或Iterable<T>
:這實際上取決於你認為客戶對你的API的期望。 需要考慮的事項:
Iterable<T>
; ImmutableSet<T>
嗎? 如果沒有,請使用Iterable<T>
;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.