簡體   English   中英

一種方法,將可變數據結構聲明為輸出並實際返回不可變數據結構

[英]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> ;
  • 否則,您可能希望遵循Robustness原則 ,該原則指出“輸入類型中的逆變和輸出類型中的協變”。 換句話說,為參數類型選擇最抽象的類型,並為返回類型選擇最具體的類型。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM