編程界的小學生
一、概念
接口隔離原則:Interface Segregation Principle,簡稱ISP。客戶端(接口調用者)不應該被迫依賴他不需要的接口。
二、如何理解“接口”
如何理解接口隔離原則中的接口二字?
分爲三個方面
- 一個類裏的一組API接口
- 單個API接口
- OOP中的interface的概念
三、“接口”解釋
1、一個類裏的一組API接口
1.1、案例
用戶系統提供了一些接口(比如註冊、登錄、查詢用戶信息等非敏感操作給其他系統使用)。
1.2、代碼
public interface UserService {
boolean register(String cellphone, String password);
boolean login(String cellphone, String password);
UserInfo getUserInfoById(long id);
UserInfo getUserInfoByCellphone(String cellphone);
}
public class UserServiceImpl implements UserService {
// ...
}
但是新的管理系統需要我們提供根據手機號刪除用戶的接口,這時候就很危險了,因爲刪除操作是很敏感的行爲。如果在上面的UserService裏添加deleteUserByCellphone
接口的話就違背了接口隔離原則,因爲其他業務系統都在依賴這個UserService,這也就意味着其他業務系統都有了deleteUserByCellphone
這個接口的權限,很危險。所以按照接口隔離原則需要將這個敏感接口單獨放到一個其他Service裏,比如RestrictedUserService#deleteUserByCellphone
來供新管理系統使用。最終完整代碼如下
public interface UserService {
boolean register(String cellphone, String password);
boolean login(String cellphone, String password);
UserInfo getUserInfoById(long id);
UserInfo getUserInfoByCellphone(String cellphone);
}
public interface RestrictedUserService {
boolean deleteUserByCellphone(String cellphone);
boolean deleteUserById(long id);
}
public class UserServiceImpl implements UserService, RestrictedUserService {
// ...省略實現代碼...
}
爲什麼是UserServiceImpl實現了兩個接口,而不是單獨的RestrictedUserServiceImpl去實現RestrictedUserService?
因爲我這裏是RPC接口,直接對外暴露Service層就行。Service裏僅有一個接口。
2、單個API接口
2.1、案例
也就是把接口理解成單個方法,也就是說方法的設計功能要單一,不要將多個不同的功能邏輯放到一個方法中實現,這裏我們的單一職責原則也是如此,所有原則大方向都一樣,只是某些點不同。所以不要糾結。
比如看下面一個統計的代碼
2.2、代碼
public class Statistics {
private Long max;
private Long min;
private Long average;
private Long sum;
private Long percentile99;
private Long percentile999;
//...省略constructor/getter/setter等方法...
}
public Statistics count(Collection<Long> dataSet) {
Statistics statistics = new Statistics();
statistics.setMax(...);
statistics.setMin(...);
statistics.setAverage(...);
//...等等
return statistics;
}
2.3、分析
上面的count函數表面看功能不夠單一,違背了單一職責原則、接口(因爲這裏的接口說的就是方法,)隔離原則,因爲它這個count幹了N件事情,按照接口隔離原則來看應該把它拆分成如下幾個粒度更小的方法
public Long max(Collection<Long> dataSet) { //... }
public Long min(Collection<Long> dataSet) { //... }
public Long average(Colletion<Long> dataSet) { //... }
// ...省略其他統計函數...
這個是需要看業務場景的,如果你只要統計max和min,那麼拆分粒度更小的越好,越不會違背接口隔離原則。因爲如果不拆分直接用count的話,需要多查幾次其他函數,比如average,這些都是無用功,浪費性能不說,其他函數出了問題還會影響主流程。但是如果業務場景就是需要統計全部的話,那麼count這個方法也沒毛病,不會違背接口隔離原則。所有的設計原則、設計模式都是爲了解決問題而生,所以沒有絕對,取決於業務場景。
3、OOP中的interface的概念
面向接口編程,interface隔離,單一功能。不要把全部方法都放到一個interface裏,根據業務適當拆分多個interface。