1. 單一職責原則
基本介紹:一個類只負責一項職責,完成一個單一的功能。
錯誤的示範
package principle.singleresponsibility.error;
/**
* 單一職責錯誤示範
* @author huangfu
*/
public class SingleResponsibilityError {
public void mobile (String vehicle){
System.out.println(vehicle + "在公路上跑!");
}
}
package principle.singleresponsibility.error;
/**
* 單一職測錯誤的示範的測試
* @author huangfu
*/
public class TestSingleResponsibilityError {
public static void main(String[] args) {
SingleResponsibilityError singleResponsibilityError = new SingleResponsibilityError();
singleResponsibilityError.mobile("汽車");
singleResponsibilityError.mobile("輪船");
singleResponsibilityError.mobile("飛機");
}
}
結果
汽車在公路上跑!
輪船在公路上跑!
飛機在公路上跑!
上述就違反了單一職責原則,對於不同的交通工具,代碼邏輯完全耦合在一起,我們無論修改那一類的交通工具,都會影響其他兩種數據
正確的示範
定義接口
package principle.singleresponsibility.correct;
/**
* @author huangfu
*/
public interface TrafficTool {
/**
* 交通工具
* @param trafficToolName
*/
void mobile(String trafficToolName);
}
定義基類,這個主要是對一類的交通工具進行抽象定義,具體的實現可以由子類實現也可直接使用父類的方法
package principle.singleresponsibility.correct.base;
import principle.singleresponsibility.correct.TrafficTool;
/**
* 陸地交通工具
* @author huangfu
*/
public abstract class LandTrafficTool implements TrafficTool {
@Override
public void mobile(String trafficToolName) {
System.out.println(trafficToolName + "在陸地跑!");
}
}
package principle.singleresponsibility.correct.base;
import principle.singleresponsibility.correct.TrafficTool;
/**
* 海上交通工具
* @author huangfu
*/
public abstract class MaritimeTrafficTool implements TrafficTool {
@Override
public void mobile(String trafficToolName) {
System.out.println(trafficToolName + "在海上跑!");
}
}
package principle.singleresponsibility.correct.base;
import principle.singleresponsibility.correct.TrafficTool;
/**
* 天空交通工具
* @author huangfu
*/
public abstract class SkyTrafficTool implements TrafficTool {
@Override
public void mobile(String trafficToolName) {
System.out.println(trafficToolName + "在天空上飛");
}
}
定義具體的實現,可以使用抽象方法也可自己實現邏輯
package principle.singleresponsibility.correct;
import principle.singleresponsibility.correct.base.SkyTrafficTool;
/**
* 飛機交通工具
* @author huangfu
*/
public class AircraftTrafficTool extends SkyTrafficTool {
@Override
public void mobile(String trafficToolName) {
super.mobile(trafficToolName);
}
}
package principle.singleresponsibility.correct;
import principle.singleresponsibility.correct.base.LandTrafficTool;
/**
* 汽車交通工具
* @author huangfu
*/
public class CarTrafficTool extends LandTrafficTool {
@Override
public void mobile(String trafficToolName) {
super.mobile(trafficToolName);
}
}
package principle.singleresponsibility.correct;
import principle.singleresponsibility.correct.base.MaritimeTrafficTool;
/**
* 輪船類交通工具
* @author huangfu
*/
public class SteamshipTrafficTool extends MaritimeTrafficTool {
@Override
public void mobile(String trafficToolName) {
super.mobile(trafficToolName);
}
}
package principle.singleresponsibility.correct;
import principle.singleresponsibility.correct.base.LandTrafficTool;
/**
* 特殊的交通工具:馬
* @author huangfu
*/
public class HorseLandTrafficTool extends LandTrafficTool {
@Override
public void mobile(String trafficToolName) {
System.out.println(trafficToolName + "在大草原上跑!");
}
}
測試類
package principle.singleresponsibility.correct;
/**
* @author huangfu
*/
public class TestTrafficTool {
public static void main(String[] args) {
//汽車類
CarTrafficTool carTrafficTool = new CarTrafficTool();
//飛機類
AircraftTrafficTool aircraftTrafficTool = new AircraftTrafficTool();
//輪船類
SteamshipTrafficTool steamshipTrafficTool = new SteamshipTrafficTool();
//特殊的交通工具 馬
HorseLandTrafficTool horseLandTrafficTool = new HorseLandTrafficTool();
carTrafficTool.mobile("蘭博基尼");
aircraftTrafficTool.mobile("南航");
steamshipTrafficTool.mobile("泰坦尼克號");
horseLandTrafficTool.mobile("汗血寶馬");
}
}
結果
蘭博基尼在陸地跑!
南航在天空上飛
泰坦尼克號在海上跑!
汗血寶馬在大草原上跑!
上述的完全的描述了單一職責的原則,對莫一類交通工具的修改,並不會影響到全局的功能,也可以基於自己的需求來定製自己的交通工具,而不會對全局的功能產生影響!
如何理解單一職責原則呢?
對於單一職責原則我的理解是:一個類只負責完成一個職責或者功能。不要涉及大而全的類,要設計粒度小、功能單一的類。單一職責原則是爲了實現代碼高內聚、低耦合,提高代碼的複用性、可讀性、可維護性。
是否有必要對類做一個精準的劃分呢?
其實對於不同的業務場景對於單一職責原則的理解都是不一樣的,我舉個例子是我在極客時間上王爭大佬的《設計模式之美》舉的一個例子,我覺的甚好,充分的說明了,在不同的業務場景下,類的職責劃分也不盡相同!
我們模擬一個在社交產品中描述用戶信息的類
package principle.singleresponsibility.entity;
/**
* 用戶信息
* @author huangfu
*/
public class UserInfo {
private String userId;
private String userName;
private String sex;
private Integer age;
private String email;
private String phone;
private long createTime;
private long lastLoginTime;
/**
* 省
*/
private String provinceOfAddress;
/**
* 市
*/
private String cityOfAddress;
/**
* 區
*/
private String regionOfAddress;
/**
* 詳細地址
*/
private String detailedAddress;
}
主要爭論有兩點,第一是覺得這個類符合
單一職責,因爲包含的都是跟用戶相關的信息,所有的屬性和方法都隸屬於用戶這樣一個業務模型,滿足單一職責原則!
持不相同的觀點:因爲這個類裏面地址所佔比重比較高,所以應該將地址單獨抽出來,形成一個userAddress類!這樣兩個類的職責就更加單一了!
其實兩種說法都對,但是他們沒有區分業務場景,剛剛也說了,不同的業務模型所對應的設計方案也不盡相同
如果說在社交產品中,地址信息和其他信息完全一致都是做展示用,第一種說法就對,沒有必要拆分,他們確實屬於一個業務模型,但是如果後來產品做大,用戶的地址信息可能會用作用戶的收件地址,那麼第二種方式就對,因爲用戶信息和物流信息並不屬於一個業務模型!
那麼我們還可以在思考,公司越做越好,肯定不止一個社交產品。公司領導希望所有的社交產品的賬號和用戶信息互通,那麼此時我們需要將 userName
,sex
,phone
等信息也拆分出來,以供其他系統使用!
那麼我們如何判斷我們的類是否足夠單一呢?
不同的應用場景、不同階段的需求背景、不同的業務層面,對同一個類的職責是否單一,可能會有不同的判定結果。實際上,一些側面的判斷指標更具有指導意義和可執行性,比如,出現下面這些情況就有可能說明這類的設計不滿足單一職責原則:
- 類中的代碼行數、函數或者屬性過多;
- 類依賴的其他類過多,或者依賴類的其他類過多;
- 私有方法過多;
- 比較難給類起一個合適的名字;
- 類中大量的方法都是集中操作類中的某幾個屬性。
總結
事實上,單一職責設計原則正式代碼 高內聚低耦合 設計的基石,他通過拆分不同業務,避免不相關的業務耦合在一起,從而提高了代碼的高內聚;同時因爲類的職責單一,他的耦合性也會相應降低,從而完成開發中一直提倡的 高內聚,低耦合
!
歡迎關注公衆號 關注公衆號,回覆架構師,提供各類技術的學習資料提供參閱!