接口隔離原則
基本介紹
接口隔離原則(Interface Segregation Principle, ISP),意爲使用多個專門的接口,而不使用單一的總接口,即客戶端不應該依賴那些它不需要的接口。
根據接口隔離原則,當一個接口太大時,我們需要將它分割成一些更細小的接口,使用該接口的客戶端僅需知道與之相關的方法即可。每一個接口應該承擔一種相對獨立的角色,不幹不該乾的事,該乾的事都要幹。這裏的“接口”往往有兩種不同的含義:一種是指一個類型所具有的方法特徵的集合,僅僅是一種邏輯上的抽象;另外一種是指某種語言具體的“接口”定義,有嚴格的定義和結構,比如Java語言中的interface。對於這兩種不同的含義,接口隔離原則的表達方式以及含義都有所不同:
- 當把“接口”理解成一個類型所提供的所有方法特徵的集合的時候,這就是一種邏輯上的概念,接口的劃分將直接帶來類型的劃分。可以把接口理解成角色,一個接口只能代表一個角色,每個角色都有它特定的一個接口,此時,這個原則可以叫做“角色隔離原則”。
- 如果把“接口”理解成狹義的特定語言的接口,那麼接口隔離原則表達的意思是指接口僅僅提供客戶端需要的行爲,客戶端不需要的行爲則隱藏起來,應當爲客戶端提供儘可能小的單獨的接口,而不要提供大的總接口。在面向對象編程語言中,實現一個接口就需要實現該接口中定義的所有方法,因此大的總接口使用起來不一定很方便,爲了使接口的職責單一,需要將大接口中的方法根據其職責不同分別放在不同的小接口中,以確保每個接口使用起來都較爲方便,並都承擔某一單一角色。接口應該儘量細化,同時接口中的方法應該儘量少,每個接口中只包含一個客戶端(如子模塊或業務邏輯類)所需的方法即可,這種機制也稱爲“定製服務”,即爲不同的客戶端提供寬窄不同的接口。
代碼示例
下面我們一個例子來加深對接口隔離原則的理解:
public interface IBehavior {
void eat(); // 喫
void go(); // 走
void run(); // 跑
void flay(); // 飛
}
public class Dog implements IBehavior {
@Override
public void eat() {
System.out.println("狗在喫東西");
}
@Override
public void go() {
System.out.println("狗在走路");
}
@Override
public void run() {
System.out.println("狗在跑");
}
@Override
public void flay() {
}
}
public class Snake implements IBehavior {
@Override
public void eat() {
System.out.println("蛇會喫東西");
}
@Override
public void go() {
}
@Override
public void run() {
}
@Override
public void flay() {
}
}
public class Bird implements IBehavior {
@Override
public void eat() {
System.out.println("鳥會喫東西");
}
@Override
public void go() {
}
@Override
public void run() {
}
@Override
public void flay() {
System.out.println("鳥會飛");
}
}
上述代碼中有一個IBehavior
接口,有eat
、go
、run
、flay
四個方法,分別用來描述動物的行爲,此接口擁有三個實現類,分別是Dog
、Snake
、Bird
,代表狗、蛇、鳥三種動物,但是並非所有動物都擁有這四個行爲,有一些行爲是不需要,因此此接口違背了接口隔離原則,下面我們來進行重構:
public interface IBehaviorEat {
void eat(); // 喫
}
public interface IBehaviorFly {
void flay(); // 飛
}
public interface IBehaviorGo {
void go(); // 走
void run(); // 跑
}
public class Dog implements IBehaviorEat,IBehaviorGo {
@Override
public void eat() {
System.out.println("狗在喫東西");
}
@Override
public void go() {
System.out.println("狗在走路");
}
@Override
public void run() {
System.out.println("狗在跑");
}
}
public class Snake implements IBehaviorEat {
@Override
public void eat() {
System.out.println("蛇會喫東西");
}
}
public class Bird implements IBehaviorEat, IBehaviorFly {
@Override
public void eat() {
System.out.println("鳥會喫東西");
}
@Override
public void flay() {
System.out.println("鳥會飛");
}
}
我們對動物的行爲進行了歸類,抽象到不同的接口上,不同的動物可以單獨去實現這些行爲,也就避免了去實現多餘行爲的問題,滿足了接口隔離原則的要求。