軟體架構設計原則之單一職責原則
單一職責(Simple Responsibility Pinciple,SRP)是指不要存在多於一個導致類變更的原因。假設我們有一個類負責兩個職責,一旦發生需求變更,修改其中一個職責的邏輯程式碼,有可能導致另一個職責的功能發生故障。這樣一來,這個類就存在兩個導致類變更的原因。如何解決這個問題呢?將兩個職責用兩個類來實現,進行解耦。後期需求變更維護互不影響。這樣的設計,可以降低類的複雜度,提高類的可讀性,提高系統的可維護性,降低變更引起的風險。總體來說,就是一個類、介面或方法只負責一項職責。
接下來,我們來看程式碼例項,還是用課程舉例,我們的課程有直播課和錄播課。直播課不能快進和快退,錄播課程可以任意地反覆觀看,功能職責不一樣。還是先建立一個Course類:
public classCourse {
public voidstudy(String courseName){
if("直播課".equals(courseName)){
System.out.println(courseName + "不能快進");
}else{
System.out.println(courseName + "可以反覆回看");
}
}
}
看呼叫程式碼:
public static voidmain(String[] args) { Course course = newCourse(); course.study("直播課"); course.study("錄播課"); }
從上面的程式碼來看,Course類承擔了兩種處理邏輯。假如現在要對課程進行加密,直播課程和錄播課程的加密邏輯不一樣,必須修改程式碼。而修改程式碼的邏輯勢必會相互影響,容易帶來不可控的風險。我們對職責進行解耦,來看程式碼,分別建立兩個類:LiveCourse和ReplayCourse。
LiveCourse類的程式碼如下:
public classLiveCourse { public voidstudy(String courseName){ System.out.println(courseName + "不能快進看"); } } ReplayCourse類的程式碼如下: public classReplayCourse { public voidstudy(String courseName){ System.out.println(courseName + "可以反覆回"); } }
呼叫程式碼如下:
public static voidmain(String[] args) {
LiveCourse liveCourse = newLiveCourse();
liveCourse.study("直播課");
ReplayCourse replayCourse = newReplayCourse();
replayCourse.study("錄播課");
}
業務繼續發展,課程要做許可權。沒有付費的學員可以獲取課程基本資訊,已經付費的學員可以獲得視訊流,即學習許可權。那麼在控制課程層面上至少有兩個職責。我們可以把展示職責和管理職責分離開來,都實現同一個抽象依賴。設計一個頂層介面,建立ICourse介面:
public interfaceICourse {
//獲得基本資訊
String getCourseName();
//獲得視訊流
byte[]getCourseVideo();
//學習課程
voidstudyCourse();
//退款
voidrefundCourse();
}
我們可以把這個介面拆成兩個介面:ICourseInfo和ICourseManager。
ICourseInfo介面的程式碼如下:
public interfaceICourseInfo {
String getCourseName();
byte[]getCourseVideo();
}
ICourseManager介面的程式碼如下:
public interfaceICourseManager {
voidstudyCourse();
voidrefundCourse();
}
來看一下類圖,如下圖所示。
下面我們來看一下方法層面的單一職責設計。有時候我們會偷懶,把一個方法寫成下面這樣:
private voidmodifyUserInfo(String userName,String address){
userName = "Tom";
address = "Changsha";
}
還可能寫成這樣:
private voidmodifyUserInfo(String userName,String... fileds){
userName = "Tom";
// address = "Changsha";
}
private voidmodifyUserInfo(String userName,String address,booleanbool){
if(bool){
}else{
}
userName = "Tom";
address = "Changsha";
}
顯然,上面的modifyUserInfo()方法承擔了多個職責,既可以修改userName,也可以修改address,甚至更多,明顯不符合單一職責。我們做如下修改,把這個方法拆成兩個方法:
private voidmodifyUserName(String userName){
userName = "Tom";
}
private voidmodifyAddress(String address){
address = "Changsha";
}
修改之後,開發起來簡單,維護起來也容易。我們在實際開發中會有專案依賴、組合、聚合這些關係,還有專案的規模、週期、技術人員的水平、對進度的把控,很多類都不符合單一職責。但是,我們在編寫程式碼的過程,儘可能地讓介面和方法保持單一職責,對專案後期的維護是有很大幫助的。