Head First Design Patterns一書介紹了以下 UML 作為觀察者模式的示例:

這張圖中讓我印象深刻的是Subject和Observer介面之間的關聯關系。據我了解Java介面,它們不能以這種方式實作“有”關系。
當我看幾頁后提供的實作示例時,我發現介面果然是普通的舊介面:
public interface Subject {
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObservers;
}
public interface Observer {
public void update(float temp, float humidity, float pressure);
}
相反,關聯關系是在具體WeatherData和Display類中實作的:
public class WeatherData implements Subject {
private List<Observer> observers;
//more code
}
這不符合UML,我覺得有點不對勁。為什么不直接實作Subject為抽象類呢?UML 規范是否形式化了將介面與另一個介面相關聯的想法?
uj5u.com熱心網友回復:
你的提問是對的。讓我們看看為什么事情是這樣的:
- 介面代表合約。在Java中,契約主要是關于一組方法。在 UML 中,它可以更廣泛,例如關于操作(方法)、屬性(欄位)、關聯(不是 java 語言特性:有幾種實作它們的方法)或約束(前置條件、后置條件、不變數、... )。
- 類必須履行它們實作/實作的介面的契約。在 Java 中,編譯器只會驗證類是否實作了介面所需的方法并具有正確的簽名。開發者永遠不會期望更多,即 java 類的行為符合介面的檔案。在 UML 中,您同樣期望一個類為自己提供介面所承諾的所有特性(參見此處)。
- 規則如何執行?在 Java 中,您必須明確:必須提供所有方法,否則您將收到編譯錯誤。如果您使用 TDD,您還可以預見一組測驗,以驗證物件是否根據介面的合同行為。在 UML 中,您可能會產生歧義,因為您不必在圖表中顯示所有內容。因此,如果您不顯示類特征或關聯,并不意味著不存在這樣的東西:該東西可能在模型中,但未顯示在特定圖表中。所以如果一個類實作了一個介面,你可以假設它提供了元素,即使它們沒有在圖中顯示。如果您使用這種模棱兩可的圖表進行代碼生成,則代碼將無法編譯。
回到你的觀察者:
- 該圖告訴我們 與
Subject有一個可導航的關聯Observer。在代碼中,你不能實作,甚至不能直接在介面中宣告這種關系。Subject然而,介面應允許注冊和洗掉的事實Observers暗示了這種關聯。 - 該圖沒有告訴我們
WheatherData與CurrentConditionDisplay. 但原則上,他們應該,因為這些類分別實作Subject和Observer。這使圖表模棱兩可。然而,如果我們相信這些類符合介面,我們可以不用顯示額外的關聯,只是假設它們必須在這里。此外,嚴格的 UML 合規性需要在這里添加 3 個這樣的關聯,使圖表更難閱讀。
現在,正如您所說的那樣,我們可以使用抽象類而不是介面來實作設計模式。但由于 Java 不允許多重繼承,這種方法將禁止主體或觀察者處于其他類層次結構中。
一些額外的背景
首先,觀察者模式——就像Heads first Design Pattern中的所有模式一樣——起源于GoF。有趣的是,GoF 早于 UML 和 Java。如果需要多重繼承,它的模式只使用類繼承。當書中提到“介面”時,它只是關于類暴露的隱式介面,通常是抽象類。
當 Java 出現時,轉換所有這些設計模式是一個挑戰,明確區分介面(在 Java 意義上)和抽象類。這就是為什么您經常會在這些模式的類圖中找到幾個變體的原因。
首當其沖也不例外。這本優秀書籍的目標是在編碼中使用模式進行教學。因此,其圖表的主要目的是傳達設計意圖,而不是教授嚴格使用高級 UML。所以他們使用了有時可能在形式上模棱兩可的圖表。總的來說,我認為他們做得很好。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/429034.html
