Interface Segregation Principle
動機
當我們試圖去設計軟件應用時,我們要仔細思考如何去抽象一個包含多個子模塊的模塊。假設模塊僅由一個類構成,我們可以用一個接口來實現系統的抽象。不過,假如我們想擴展我們的應用,增加另一個模塊,而這個模塊只包含原系統的一部分子模塊,那我們就被迫地去實現這整個接口,然后編寫一些虛假的方法。這種接口我們稱為是胖接口 fat interface
或者被污染的接口。擁有一個被污染的接口不是一個好的解決方案,而且可能給系統帶來不恰當的行為。
ISP 規定客戶端不應被強迫實現他們不需要使用的接口。應優先選擇基于方法分組,分別服務各小模塊的小型接口,而不是一個大而全的胖接口。
目的
客戶端不應被迫依賴他們不必使用的接口。
例子
以下是一個違背 ISP 的例子。 我們有個 Manager
類來管理工人。還有2種類型的工人,一種工作效率達到平均水平,一種工作效率非常高。兩種類型的工人每天都需要午休時間吃飯。?現在一些機器人也進入公司,但是這些機器人不需要吃東西也就不需要午休了。一方面 Robot
類需要實現 IWorker
接口,因為他們確實要干活。另一方面,它們不需要實現 IWorker
接口,因為它們不需要吃東西。
這就是為什么在這種情形下 IWorker
被認為是受污染的接口。
如果我們繼續保持現有設計,新的 Robot
類就被迫要實現 eat
方法了。我們也寫一個什么也不做的偽類(比如說每天1秒的午休), 然后將給應用帶來非預期的影響(比如說經理們看到的午休報告會多于實際的人數)。
根據 ISP ,靈活的設計中不會存在被污染的類。在以上這個情況,接口 IWorker
應拆成2個不同的小接口。
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個獨立的接口,新 Robot
就不用再被迫實現這個 eat
方法了。同樣,如果我們需要給機器人添加另一個功能,比如說,充電,我們只需要再建一個 IRechargeble
接口,并在其中規定 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();
}
}
總結
如果原有設計已經完成,已有的胖接口可以通過適配器模式來進行拆分。
就如其他原則一樣 ISP 也需要耗費額外的時間和精力去應用它,也會使代碼更加復雜。不過,它也帶來更靈活的設計。如果在不必要的地方也去使用 ISP 的話,會導致一堆只有單個方法的接口。所以,ISP 的應用需要基于經驗和常識來識別在未來比較有可能需要擴展的代碼區域。
上一篇: 依賴倒置原則
下一篇: 單一職責原則
目錄: http://www.lxweimin.com/p/af861220a6cc