单一职责原理讲解coding
生活随笔
收集整理的這篇文章主要介紹了
单一职责原理讲解coding
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
單一職責(zé)原則是說一個(gè)類只有一個(gè)發(fā)生變更的原因,這個(gè)是在類層之上的,那在接口層次,方法層次,也要遵循單一原則,那我們現(xiàn)在結(jié)合一些例子來說明一下,那單一職責(zé)的好處呢,首先降低類的復(fù)雜性,提高可讀性,提高維護(hù)性,最重要的是變更的時(shí)候風(fēng)險(xiǎn)率降低,那我們現(xiàn)在結(jié)合例子一起來體會(huì)一下,單一職責(zé)原則,首先呢我們現(xiàn)在有一個(gè)類
這個(gè)類圖還是非常非常簡(jiǎn)單的,其實(shí)是由Test創(chuàng)建這兩個(gè)類,這個(gè)Bird類現(xiàn)在已經(jīng)不用了,那職責(zé)在類的層次上,還是比較清晰的,那剛剛說的是類的職責(zé)上,那我們?cè)倏匆幌略诮涌诩?jí)別上,還是用我們的課程舉例,ICourse是一個(gè)接口
package com.learn.design.principle.singleresponsibility;/*** 鳥主要的移動(dòng)方式我們來學(xué)一下* * @author Leon.Sun**/
public class Bird {/*** 主要是用翅膀飛* 這里面我們?cè)黾右粋€(gè)birdName* 鳥的名稱* * * @param birdName*/public void mainMoveMode(String birdName){/*** 這里要做一個(gè)判斷* 這個(gè)就非常符合我們的日常開發(fā)* 一個(gè)需求來說* 我們?cè)谶@里做一個(gè)修改* 其實(shí)是最快的方式* 我們?cè)趯?shí)際開發(fā)中還要考慮開發(fā)的成本* 時(shí)間,進(jìn)度* 完全遵守單一原則* 有的時(shí)候還是要看實(shí)際情況的* 但是我們有一顆按照原則寫代碼的心* 條件允許的情況下* 還是要大家來遵守這些設(shè)計(jì)原則* 那需求現(xiàn)在增加了鴕鳥* 那我們?cè)谠械念惣右粋€(gè)判斷* * */if("鴕鳥".equals(birdName)){/*** 如果是鴕鳥的話* 用腳走* 鴕鳥用腳走* * 這里面有bug了* System.out.println(birdName+"用翅膀飛");* 下一行又走到了這里* 這里就是一個(gè)典型的一個(gè)例子* 那我們?cè)跀U(kuò)展的時(shí)候* 對(duì)于一些邊界* 我們這里增加了if* 但是下邊并沒有放到else里* 這種情況也比較常見* 正確的寫法應(yīng)該是這樣的* 如果繼續(xù)擴(kuò)展下來* 包括企鵝* 企鵝也是鳥* 企鵝也是用腳走* 那鴕鳥跟企鵝呢* 我們還可以細(xì)分一下* 那如果現(xiàn)在再傳來一些特殊的鳥類* 那我們的這個(gè)方法還要繼續(xù)擴(kuò)展* 還記得我們說的* 單一職責(zé)原則其中有一個(gè)最重要的好處* 他就是變更時(shí)風(fēng)險(xiǎn)率降低* 那現(xiàn)在是不遵循單一原則的* 所以風(fēng)險(xiǎn)還是比較大* 當(dāng)然我們看到的這個(gè)方法還比較簡(jiǎn)單* 那實(shí)際的業(yè)務(wù)比這個(gè)復(fù)雜* 邊界比這個(gè)判斷要 更多一些* 那我們現(xiàn)在從類的形式來把這個(gè)拆分開* */System.out.println(birdName+"用腳走");}else{System.out.println(birdName+"用翅膀飛");}}
}
package com.learn.design.principle.singleresponsibility;/*** 我們 創(chuàng)建一個(gè)類FlyBird* * * @author Leon.Sun**/
public class FlyBird {public void mainMoveMode(String birdName){System.out.println(birdName+"用翅膀飛");}
}
package com.learn.design.principle.singleresponsibility;/*** 我們?cè)賱?chuàng)建一個(gè)類WalkBird* 走路的鳥* * * @author Leon.Sun**/
public class WalkBird {public void mainMoveMode(String birdName){System.out.println(birdName+"用腳走");}
}
package com.learn.design.principle.singleresponsibility;/*** 我們寫一個(gè)測(cè)試類* * * @author Leon.Sun**/
public class Test {public static void main(String[] args) {/*** new一個(gè)bird* 我們傳進(jìn)去一個(gè)大雁* 大雁用翅膀飛* 我現(xiàn)在再傳一個(gè)鴕鳥* 那鴕鳥用翅膀飛* 就不對(duì)* 因?yàn)轼r鳥飛不起來* 那我們?cè)倏匆幌逻@個(gè)類* * 可以看到大雁沒有問題* 用翅膀飛* 那鴕鳥用腳走* 鴕鳥用翅膀飛* * */
// Bird bird = new Bird();
// bird.mainMoveMode("大雁");
// bird.mainMoveMode("鴕鳥");/*** 那我們飛的鳥和走的鳥都區(qū)分一下* 這塊還是比較簡(jiǎn)單的* 我們應(yīng)用層來判斷這個(gè)邏輯* 如果是大雁* 我們就用FlyBird* 如果是鴕鳥我們就用行走的Bird* 那這個(gè)就是類的單一原則的體現(xiàn)* 我們把一個(gè)類進(jìn)行拆分* 這樣我們就使每個(gè)類的方法職責(zé)單一的* 比較簡(jiǎn)單* 也不至于引入的時(shí)候出現(xiàn)新的問題* 那我們來看一下類圖* * */FlyBird flyBird = new FlyBird();flyBird.mainMoveMode("大雁");WalkBird walkBird = new WalkBird();walkBird.mainMoveMode("鴕鳥");}
}
課程類實(shí)現(xiàn)兩個(gè)接口,我們可以通過實(shí)現(xiàn)一個(gè)接口或者多個(gè)接口,來組合出這個(gè)實(shí)現(xiàn)類的一個(gè)實(shí)現(xiàn),但是我也可以實(shí)現(xiàn)一個(gè)接口,也就是我們這個(gè)實(shí)現(xiàn)類實(shí)現(xiàn)什么職責(zé)呢,都是有清楚明確的定義,復(fù)雜性也是降低了,復(fù)雜性降低了可讀性也就提高了,可讀性提高了也就更容易維護(hù)了,可讀性也就提高了,同時(shí)變更引起的影響降低了,一個(gè)接口的更改只對(duì)相應(yīng)的實(shí)現(xiàn)類有影響,與其他的接口無關(guān),這一點(diǎn)對(duì)項(xiàng)目的幫助是非常大的,這個(gè)就是從接口級(jí)別上來講,單一職責(zé),剛剛類,接口,我們?cè)賮砜纯磫我宦氊?zé)
package com.learn.design.principle.singleresponsibility;/*** 這個(gè)是一個(gè)接口* 我們來看一下這個(gè)接口* 對(duì)于課程來說* 獲得課程的名字* 獲得課程的視頻* 那在接口的基礎(chǔ)上做單一原則的話* 也就是ICourse這個(gè)接口* 可不只有一個(gè)職責(zé)* 首先一個(gè)大的職責(zé)是獲得課程的信息* 比如名稱和視頻字節(jié)流* 另外一個(gè)職責(zé)是管理課程* 和課程內(nèi)容無關(guān)* 例如學(xué)習(xí)課程* 那如果學(xué)習(xí)課程需要獲取name* 視頻字節(jié)流* 如果退了這個(gè)課程呢* 可能就獲取不了這個(gè)名字和字節(jié)流了* 因?yàn)檫@個(gè)課程已經(jīng)被我退掉了* 那退會(huì)影響獲取內(nèi)容的變化* 這兩個(gè)職責(zé)是互相影響的* 現(xiàn)在我們退了這個(gè)課程* 那獲取課程信息的時(shí)候* 我們這個(gè)實(shí)現(xiàn)就獲取不到* 就可以了* 那整體來看* 這個(gè)接口兩個(gè)職責(zé)* 獲取課程相關(guān)信息* 還有課程管理上的相關(guān)處理* 那我們就可以把這個(gè)接口拆成兩個(gè)接口* 一個(gè)是獲取課程信息的接口* 另外是課程管理的接口* 我們來嘗試一下* * * @author Leon.Sun**/
public interface ICourse {/*** 我是可以獲得課程的名稱的* * * @return*/String getCourseName();/*** 我還可以獲得一個(gè)視頻* 拿到一個(gè)字節(jié)流* * @return*/byte[] getCourseVideo();/*** 學(xué)習(xí)課程* */void studyCourse();/*** 退款* */void refundCourse();}
package com.learn.design.principle.singleresponsibility;public interface ICourseManager {/*** 然后把這個(gè)拿到這邊* */void studyCourse();void refundCourse();
}
package com.learn.design.principle.singleresponsibility;/*** 注意這個(gè)關(guān)鍵字是interface* * @author Leon.Sun**/
public interface ICourseContent {/*** 我們把這兩個(gè)拿到這里邊* * @return*/String getCourseName();byte[] getCourseVideo();
}
package com.learn.design.principle.singleresponsibility;/*** 我們現(xiàn)在來實(shí)現(xiàn)一個(gè)Course的實(shí)現(xiàn)類* 他來實(shí)現(xiàn)ICourseManager這個(gè)接口* 同時(shí)來實(shí)現(xiàn)ICourseContent這個(gè)接口* CourseImpl實(shí)現(xiàn)類實(shí)現(xiàn)這兩個(gè)接口* 我們來看一下類圖* * * @author Leon.Sun**/
public class CourseImpl implements ICourseManager,ICourseContent {@Overridepublic void studyCourse() {}@Overridepublic void refundCourse() {}@Overridepublic String getCourseName() {return null;}@Overridepublic byte[] getCourseVideo() {return new byte[0];}
}
package com.learn.design.principle.singleresponsibility;/*** 那我們簡(jiǎn)單的總結(jié)一下* 類的單一職責(zé)原則和接口方法的單一職責(zé)是一樣的* 但是我們?cè)趯?shí)際的項(xiàng)目開發(fā)中* 我們?cè)趧?chuàng)建類的時(shí)候* 包括依賴組合聚合* 受很多因素的影響* 包括我們項(xiàng)目的規(guī)模* 還有項(xiàng)目的周期* 技術(shù)人員的水平* 還有對(duì)進(jìn)度的把控* 這個(gè)都是一個(gè)平衡的因素* 那另外有一個(gè)考慮* 也就是我們?cè)跀U(kuò)展的時(shí)候* 如果我們沒有面向接口的編程* 而又非常遵循單一職責(zé)原則* 可能引起類的一個(gè)爆炸* 類的數(shù)量會(huì)比較多* 所以我們?cè)诳偨Y(jié)起來* 就是說在實(shí)際的開發(fā)中* 我們的接口和方法* 一定要做到單一職責(zé)* 這個(gè)其實(shí)還是蠻好的* 對(duì)于我們維護(hù)起來也會(huì)比較方便* 而且成本也非常低* * * @author Leon.Sun**/
public class Method {/*** 我們現(xiàn)在有一個(gè)方法叫updateUserInfo* 這里面可以更新用戶名稱* 還可以更新地址* 其實(shí)這個(gè)方法就是同時(shí)更新userName和地址* * * @param userName* @param address*/private void updateUserInfo(String userName,String address){/*** 這里是一個(gè)偽代碼* 大家認(rèn)為是一個(gè)更新的過程就可以了* * */userName = "geely";address = "beijing";}/*** 如果我們還有一種寫法* 如果是一個(gè)可變長(zhǎng)度的參數(shù)* 還有其他的properties* 其他的屬性* 那這個(gè)方法的職責(zé)就更多了* 不一定更新什么* 這里是一個(gè)可變長(zhǎng)的參數(shù)* 可變長(zhǎng)的參數(shù)肯定是放在方法最后一個(gè)位置* 聲明才可以* 這里面可能包括各種信息* 例如說他的體重* 那這個(gè)方法從命名上* 包括里面的實(shí)現(xiàn)上* 職責(zé)就不是單一的* * * @param userName* @param properties*/private void updateUserInfo(String userName,String... properties){userName = "geely";
// address = "beijing";}/*** 那更好的方式應(yīng)該是這樣的* 大家可以理解他的一個(gè)變化* 只更新名字* 這個(gè)就叫做updateUsername* 需要更新name的話* 就調(diào)用這個(gè)方法* 這兩個(gè)方法的職責(zé)是非常的單一且清晰的* 那我們?cè)趯懛椒ǖ臅r(shí)候* 經(jīng)常還會(huì)碰到這個(gè)場(chǎng)景* * * @param userName*/private void updateUsername(String userName){userName = "geely";}/*** 這個(gè)就叫做updateUserAddress* 我們把之前的那個(gè)方法拆分成兩個(gè)方法* 如果我們需要更新地址的話* 那就調(diào)用這個(gè)方法* * * @param address*/private void updateUserAddress(String address){address = "beijing";}/*** 后面多了一個(gè)布爾* 這個(gè)方法里面?zhèn)髁艘粋€(gè)布爾類型* 這就有意思了* 我們看一下* * * @param userName* @param address* @param bool*/private void updateUserInfo(String userName,String address,boolean bool){/*** 我們一般會(huì)這么寫* 也就是布爾類型要么true要么false* 其實(shí)這個(gè)方法的職責(zé)要么todo something1* 還有todo something2* 那這種情況我們就應(yīng)該把這個(gè)方法拆開* 因?yàn)檫@個(gè)方法很明顯的就是兩個(gè)職責(zé)* 如果你傳進(jìn)來的布爾你沒有使用* 如果使用的就拆開* 有布爾的存在這個(gè)方法就不會(huì)有單一的職責(zé)* 這樣開發(fā)起來簡(jiǎn)單* 維護(hù)起來也容易* * */if(bool){//todo something1}else{//todo something2}userName = "geely";address = "beijing";}}
?
總結(jié)
以上是生活随笔為你收集整理的单一职责原理讲解coding的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 单一职责原理讲解
- 下一篇: 接口隔离原则原理讲解-coding