鮮花網(wǎng)站建設(shè)的目標百度賬號
重構(gòu)類關(guān)系-Extract Interface提煉接口八
1.提煉接口
1.1.使用場景
若干客戶使用類接口中的同一子集,或者兩個類的接口有部分相同。將相同的子集提煉到一個獨立接口中。
類之間彼此互用的方式有若干種?!笆褂靡粋€類”通常意味用到該類的所有責(zé)任區(qū)。另一種情況是,某一組客戶只使用類責(zé)任區(qū)中的一個特定子集。再一種情況則是,這個類需要與所有協(xié)助處理某些特定請求的類合作。
對于后兩種情況,將真正用到的這部分責(zé)任分離出來通常很有意義,因為這樣可以使系統(tǒng)的用法更清晰,同時也更容易看清系統(tǒng)的責(zé)任劃分。如果新的類需要支持上述子集,也比較能夠看清子集內(nèi)有些什么東西。
在許多面向?qū)ο笳Z言中,這種責(zé)任劃分是通過多繼承(multiple inheritance)來實現(xiàn)的。你可以針對每組行為建立一個類,再將它們組合于同一個實現(xiàn)中。Java只提供單繼承(single inheritance),但你可以運用接口(interface)來昭示并實現(xiàn)上述需求。接口對于Java程序的設(shè)計方式有著巨大的影響,就連Smalltalk程序員都認為接口是一大進步!
Extract Superclass (336)和Extract Interface (341)之間有些相似之處。Extract Interface (341)只能提煉共通接口,不能提煉共通代碼。使用Extract Interface (341)可能造成難聞的“重復(fù)”壞味道,幸而你可以運用Extract Class (149)先把共通行為放進一個組件中,然后將工作委托該組件,從而解決這個問題。如果有不少共通行為,Extract Superclass (336)會比較簡單,但是每個類只能有一個超類。
如果某個類在不同環(huán)境下扮演截然不同的角色,使用接口就是個好主意。你可以針對每個角色以Extract Interface (341)提煉出相應(yīng)接口。另一種可以用上Extract Interface (341)的情況是:你想要描述一個類的外部依賴接口(outbound interface,即這個類要求服務(wù)提供方提供的操作)。如果你打算將來加入其他種類的服務(wù)對象,只需要求它們實現(xiàn)這個接口即可。
1.2.如何做
- 新建一個空接口。
- 在接口中聲明待提煉類的共通操作。
- 讓相關(guān)的類實現(xiàn)上述接口。
- 調(diào)整客戶端的類型聲明,令其使用該接口。
1.3.示例
TimeSheet類表示員工為客戶工作的時間表,從中可以計算客戶應(yīng)該支付的費用。為了計算這筆費用,TimeSheet需要知道員工級別,以及該員工是否有特殊技能:
// 通過Employee類對象獲取員工信息
double charge(Employee emp, int days) {int base = emp.getRate() * days;if (emp.hasSpecialSkill())return base * 1.05;else return base;
}
除了提供員工的級別和特殊技能信息外,Employee還有很多其他方面的功能,但本應(yīng)用程序只需這兩項功能。我可以針對這兩項功能定義一個接口,從而強調(diào)“我只需要這部分功能”的事實:
interface Billable {public int getRate();public boolean hasSpecialSkill();}
然后,我聲明讓Employee實現(xiàn)這個接口
class Employee implements Billable ...
完成以后,我可以修改charge()函數(shù)聲明,強調(diào)該函數(shù)只使用Employee的這部分行為
// Billable接口明確表示 只使用Employee類中部分功能
double charge(Billable emp, int days) {int base = emp.getRate() * days;if (emp.hasSpecialSkill())return base * 1.05;else return base;
}
到目前為止,我們只不過是在文檔化方面有一點收獲。單就這一個函數(shù)而言,這樣的收獲并沒有太大價值;但如果有若干個類都使用Billable接口,它就會很有用。如果我還想計算電腦租金,巨大的收獲就顯露出來了:要想計算客戶租用電腦的費用,我只需讓Computer類實現(xiàn)Billable接口,然后就可以把租用電腦的時間也填到時間表上了。