Interface Segregation Principle
動(dòng)機(jī)
當(dāng)我們?cè)噲D去設(shè)計(jì)軟件應(yīng)用時(shí),我們要仔細(xì)思考如何去抽象一個(gè)包含多個(gè)子模塊的模塊塔鳍。假設(shè)模塊僅由一個(gè)類構(gòu)成,我們可以用一個(gè)接口來實(shí)現(xiàn)系統(tǒng)的抽象畜晰。不過汽纤,假如我們想擴(kuò)展我們的應(yīng)用,增加另一個(gè)模塊,而這個(gè)模塊只包含原系統(tǒng)的一部分子模塊肢础,那我們就被迫地去實(shí)現(xiàn)這整個(gè)接口还栓,然后編寫一些虛假的方法。這種接口我們稱為是胖接口 fat interface
或者被污染的接口传轰。擁有一個(gè)被污染的接口不是一個(gè)好的解決方案蝙云,而且可能給系統(tǒng)帶來不恰當(dāng)?shù)男袨椤?/p>
ISP 規(guī)定客戶端不應(yīng)被強(qiáng)迫實(shí)現(xiàn)他們不需要使用的接口。應(yīng)優(yōu)先選擇基于方法分組路召,分別服務(wù)各小模塊的小型接口,而不是一個(gè)大而全的胖接口波材。
目的
客戶端不應(yīng)被迫依賴他們不必使用的接口股淡。
例子
以下是一個(gè)違背 ISP 的例子。 我們有個(gè) Manager
類來管理工人廷区。還有2種類型的工人唯灵,一種工作效率達(dá)到平均水平,一種工作效率非常高隙轻。兩種類型的工人每天都需要午休時(shí)間吃飯埠帕。?現(xiàn)在一些機(jī)器人也進(jìn)入公司,但是這些機(jī)器人不需要吃東西也就不需要午休了玖绿。一方面 Robot
類需要實(shí)現(xiàn) IWorker
接口敛瓷,因?yàn)樗麄兇_實(shí)要干活。另一方面斑匪,它們不需要實(shí)現(xiàn) IWorker
接口呐籽,因?yàn)樗鼈儾恍枰詵|西。
這就是為什么在這種情形下 IWorker
被認(rèn)為是受污染的接口蚀瘸。
如果我們繼續(xù)保持現(xiàn)有設(shè)計(jì)狡蝶,新的 Robot
類就被迫要實(shí)現(xiàn) eat
方法了。我們也寫一個(gè)什么也不做的偽類(比如說每天1秒的午休)贮勃, 然后將給應(yīng)用帶來非預(yù)期的影響(比如說經(jīng)理們看到的午休報(bào)告會(huì)多于實(shí)際的人數(shù))贪惹。
根據(jù) ISP ,靈活的設(shè)計(jì)中不會(huì)存在被污染的類寂嘉。在以上這個(gè)情況奏瞬,接口 IWorker
應(yīng)拆成2個(gè)不同的小接口。
interface IWorker{
public void work();
public void eat();
}
class Worker implements IWorker{
public void work() {
// ... working
}
public void eat() {
// ... eating in lunch break
}
}
class SuperWorker implements IWorker{
public void work() {
// ... working much more
}
public void eat() {
// ... eating in lunch break
}
}
class Robot implements IWorker{
public void work() {
// ... working
}
public void eat() {
// ... Robot doesn't need eat !!! 被迫~~~~
}
}
class Manager{
IWorker worker;
public void setWorker(IWorker w){
this.worker = w;
}
public void manage(){
this.worker.work();
}
}
再下面是遵循 ISP 的例子垫释。通過將 IWorker
拆分成2個(gè)獨(dú)立的接口丝格,新 Robot
就不用再被迫實(shí)現(xiàn)這個(gè) eat
方法了。同樣棵譬,如果我們需要給機(jī)器人添加另一個(gè)功能显蝌,比如說,充電,我們只需要再建一個(gè) IRechargeble
接口曼尊,并在其中規(guī)定 recharge
方法就行酬诀。
interface IWorkable {
public void work();
}
interface IFeedable {
public void eat();
}
class Worker implements IWorkable, IFeedable {
public void work() {
// ... working
}
public void eat() {
// ... eating in lunch break
}
}
class SuperWorker implements IWorkable, IFeedable {
public void work() {
// ... working much more
}
public void eat() {
// ... eating in lunch break
}
}
class Robot implements IWorkable {
public void work() {
// ... working
}
}
class Manager {
IWorkable worker;
public void setWorker(IWorkable w) {
this.worker = w;
}
public void manage() {
this.worker.work();
}
}
總結(jié)
如果原有設(shè)計(jì)已經(jīng)完成,已有的胖接口可以通過適配器模式來進(jìn)行拆分骆撇。
就如其他原則一樣 ISP 也需要耗費(fèi)額外的時(shí)間和精力去應(yīng)用它瞒御,也會(huì)使代碼更加復(fù)雜。不過神郊,它也帶來更靈活的設(shè)計(jì)肴裙。如果在不必要的地方也去使用 ISP 的話,會(huì)導(dǎo)致一堆只有單個(gè)方法的接口涌乳。所以蜻懦,ISP 的應(yīng)用需要基于經(jīng)驗(yàn)和常識(shí)來識(shí)別在未來比較有可能需要擴(kuò)展的代碼區(qū)域。
上一篇: 依賴倒置原則
下一篇: 單一職責(zé)原則
目錄: http://www.reibang.com/p/af861220a6cc