軟件架構設計原則之單一職責原則


單一職責(Simple Responsibility Pinciple,SRP)是指不要存在多於一個導致類變更的原因。假設我們有一個類負責兩個職責,一旦發生需求變更,修改其中一個職責的邏輯代碼,有可能導致另一個職責的功能發生故障。這樣一來,這個類就存在兩個導致類變更的原因。如何解決這個問題呢?將兩個職責用兩個類來實現,進行解耦。后期需求變更維護互不影響。這樣的設計,可以降低類的復雜度,提高類的可讀性,提高系統的可維護性,降低變更引起的風險。總體來說,就是一個類、接口或方法只負責一項職責。

接下來,我們來看代碼實例,還是用課程舉例,我們的課程有直播課和錄播課。直播課不能快進和快退,錄播課程可以任意地反復觀看,功能職責不一樣。還是先創建一個Course類:

public class Course {

    public void study(String courseName){

        if("直播課".equals(courseName)){

            System.out.println(courseName + "不能快進");

        }else{

            System.out.println(courseName + "可以反復回看");

        }

    }

}

看調用代碼:

public static void main(String[] args) {

    Course course = new Course();

    course.study("直播課");

    course.study("錄播課");

}

從上面的代碼來看,Course類承擔了兩種處理邏輯。假如現在要對課程進行加密,直播課程和錄播課程的加密邏輯不一樣,必須修改代碼。而修改代碼的邏輯勢必會相互影響,容易帶來不可控的風險。我們對職責進行解耦,來看代碼,分別創建兩個類:LiveCourse和ReplayCourse。

LiveCourse類的代碼如下:

public class LiveCourse {

    public void study(String courseName){

        System.out.println(courseName + "不能快進看");

    }

}
ReplayCourse類的代碼如下:

public class ReplayCourse {

    public void study(String courseName){

        System.out.println(courseName + "可以反復回");

    }

}

調用代碼如下:

public static void main(String[] args) {

    LiveCourse liveCourse = new LiveCourse();

    liveCourse.study("直播課");



    ReplayCourse replayCourse = new ReplayCourse();

    replayCourse.study("錄播課");

}

業務繼續發展,課程要做權限。沒有付費的學員可以獲取課程基本信息,已經付費的學員可以獲得視頻流,即學習權限。那么在控制課程層面上至少有兩個職責。我們可以把展示職責和管理職責分離開來,都實現同一個抽象依賴。設計一個頂層接口,創建ICourse接口:

public interface ICourse {

    //獲得基本信息

    String getCourseName();

    //獲得視頻流

    byte[] getCourseVideo();

    //學習課程

    void studyCourse();

    //退款

    void refundCourse();

}

我們可以把這個接口拆成兩個接口:ICourseInfo和ICourseManager。

ICourseInfo接口的代碼如下:

public interface ICourseInfo {

    String getCourseName();

    byte[] getCourseVideo();

}

ICourseManager接口的代碼如下:

public interface ICourseManager {

    void studyCourse();

    void refundCourse();

}

來看一下類圖,如下圖所示。

下面我們來看一下方法層面的單一職責設計。有時候我們會偷懶,把一個方法寫成下面這樣:

private void modifyUserInfo(String userName,String address){

    userName = "Tom";

    address = "Changsha";

}

還可能寫成這樣:

private void modifyUserInfo(String userName,String... fileds){

        userName = "Tom";

//        address = "Changsha";

}

private void modifyUserInfo(String userName,String address,boolean bool){

    if(bool){


    }else{


    }

    userName = "Tom";

    address = "Changsha";

}

顯然,上面的modifyUserInfo()方法承擔了多個職責,既可以修改userName,也可以修改address,甚至更多,明顯不符合單一職責。我們做如下修改,把這個方法拆成兩個方法:

private void modifyUserName(String userName){

    userName = "Tom";

}

private void modifyAddress(String address){

    address = "Changsha";

}

修改之后,開發起來簡單,維護起來也容易。我們在實際開發中會有項目依賴、組合、聚合這些關系,還有項目的規模、周期、技術人員的水平、對進度的把控,很多類都不符合單一職責。但是,我們在編寫代碼的過程,盡可能地讓接口和方法保持單一職責,對項目后期的維護是有很大幫助的。

關注微信公眾號『 Tom彈架構 』回復“設計模式”可獲取完整源碼。

【推薦】Tom彈架構:30個設計模式真實案例(附源碼),挑戰年薪60W不是夢

本文為“Tom彈架構”原創,轉載請注明出處。技術在於分享,我分享我快樂!
如果本文對您有幫助,歡迎關注和點贊;如果您有任何建議也可留言評論或私信,您的支持是我堅持創作的動力。關注微信公眾號『 Tom彈架構 』可獲取更多技術干貨!

其他設計原則

Tom彈架構:開閉原則(Open-Closed Principle,OCP)

Tom彈架構:依賴倒置原則(Dependence Inversion Principle,DIP)

Tom彈架構:接口隔離原則(Interface Segregation Principle, ISP)

Tom彈架構:迪米特原則(Law of Demeter LoD)

Tom彈架構:里氏替換原則(Liskov Substitution Principle,LSP)

Tom彈架構:合成復用原則(Composite/Aggregate Reuse Principle,CARP)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM