摘要:定義首先呢,我們來看一下單一職責原則的定義。只負責一項職責,這就是單一職責原則。這時候就涉及到平衡的問題,平衡單一職責原則與修改造成的開銷。嘻哈說接下來,請您欣賞單一職責原則的原創(chuàng)歌曲。
1、定義
首先呢,我們來看一下單一職責原則的定義。
就一個類而言,應該只有一個引起它變化的原因
這個說法不是很好懂,有一些抽象,不過呢,我們依舊可以嘗試著理解一下。
就一個類而言,只有一個引起它變化的原因,也就是說,除此之外,不能有其它引起變化的原因。
這樣就需要一個前提,這個類只能負責一項職責,而不能負責其他的職責,不然,其他的職責就會存在其他變化的原因了。
通俗的說,即一個類只負責一項職責。
懶人就比較喜歡這種通俗地定義,一目了然。
懶人曾經(jīng)總結(jié)過:通俗的定義,淺顯易懂;理論的定義,大腦一懵。
有同感的小伙伴請雙擊666。
2、場景餐館聚餐,通過服務(wù)員點餐
這是一個比較常見的場景,比如懶人擼了五天的代碼,身心疲憊,周末的時候呢,就約上三五個好友,去餐館(番茄餐廳)happy一下(非常單純的吃飯)。我們剛剛坐下,就來了一位很漂亮的服務(wù)員為我們點餐。
這樣一個服務(wù)員為我們點餐的場景,一般都是什么樣的流程?
第一步:客人點餐
懶人:咱呢,不但要吃飽,還要吃好!服務(wù)員,先來一份西紅柿炒雞蛋,再來一份酸辣土豆絲!!!
好友:臉呢。。。說好的臉呢。。。
服務(wù)員:你是顧客,你是上帝,你說啥就是啥,不過,你剛才說的是啥。。。
第二步:烹飪美食
西紅柿炒雞蛋,先炒雞蛋,再炒西紅柿。。。ok,出鍋。
第三步:上餐
服務(wù)員:這是您點的西紅柿炒雞蛋,請您慢用。
3、實現(xiàn)不廢話,擼代碼。
package com.fanqiekt.principle.single; /** * 服務(wù)員 * @Author: 番茄課堂-懶人 */ public class Waiter { /** * 下單 * @param dishName 菜名 */ public void order(String dishName){ System.out.println("客人點餐:" + dishName); System.out.println("開始烹飪:" + dishName); //菜品不同,做法不同。 switch (dishName){ case "西紅柿炒雞蛋": System.out.println("先炒雞蛋"); System.out.println("再炒西紅柿"); System.out.println("..."); break; case "酸辣土豆絲": System.out.println("先放蔥姜蒜"); System.out.println("再放土豆絲"); System.out.println("..."); break; } System.out.println(dishName + "出鍋"); System.out.println(dishName + "上桌啦,請您品嘗"); } }
服務(wù)員這個類比較簡單,就一個下單的方法。
為了更好的理解,懶人進行了細節(jié)的優(yōu)化(主要是很多細節(jié)懶人壓根不了解)。
package com.fanqiekt.principle.single; /** * 客戶端 * @Author: 番茄課堂-懶人 */ public class Client { public static void main(String[] args){ Waiter waiter = new Waiter(); waiter.order("西紅柿炒雞蛋"); System.out.println("-------"); waiter.order("酸辣土豆絲"); } }
客戶端這個類就相當于客人,客人負責通過服務(wù)員點餐。
客人一共點了兩道大餐,西紅柿炒雞蛋、酸辣土豆絲,我們來運行一下,看看結(jié)果。
客人點餐:西紅柿炒雞蛋 開始烹飪:西紅柿炒雞蛋 先炒雞蛋 再炒西紅柿 ... 西紅柿炒雞蛋出鍋 西紅柿炒雞蛋上桌啦,請您品嘗 ------- 客人點餐:酸辣土豆絲 開始烹飪:酸辣土豆絲 先放蔥姜蒜 再放土豆絲 ... 酸辣土豆絲出鍋 酸辣土豆絲上桌啦,請您品嘗
OK,兩個熱氣騰騰的飯菜就做好了。
我們回過頭來看一下waiter類,大家覺得這個類好不好?
肯定是不好了,那...不好在哪里?
這就好比一個小作坊,老板既負責點餐又負責下單,就跟waiter類一樣。
我們一般在小作坊吃飯,感受會怎么樣?
亂,非同一般的雜亂。上菜需要等半天,點餐的時候找不到人。
還有一個弊端,我修改了做飯的流程,會影響下單的業(yè)務(wù),增加修改的風險,為什么這么說呢?
客人A:老板,給我來一份酸辣土豆絲。
老板:好嘞,您稍等。
懶人:老板,我剛才點的西紅柿雞蛋要少放鹽啊。
老板:好的,我放鹽的時候用小點的勺子。
客人A:老板,我的菜做了嗎?我的同伴都吃完了,沒做我就不要了!
老板:您的菜已經(jīng)做了,馬上就要出鍋了。(內(nèi)心:我勒個去,剛才用小勺放鹽的時候把這哥們點的單給忘了,這就尷尬了。。。)
不難看出,當功能冗雜到一個對象中,這樣修改就會增加風險。那我們該如何避免呢?
一般比較完善的餐館,還至少會有一名廚師。
廚師做飯,服務(wù)員點餐,這樣做,有什么好處呢?
一來,結(jié)構(gòu)清晰了,各司其職,一目了然。二來,風險降低了,我修改做飯的流程,不會影響下單的業(yè)務(wù)。
只負責一項職責,這就是單一職責原則。
那我們嘗試著增加一個廚師類。
package com.fanqiekt.principle.single; /** * 廚師 * * @author 番茄課堂-懶人 */ public class Chef { /** * 做飯 * @param dishName 下單的菜名 */ public void cooking(String dishName) { System.out.println("開始烹飪:"+dishName); switch (dishName){ case "西紅柿炒雞蛋": System.out.println("先炒雞蛋"); System.out.println("再炒西紅柿"); System.out.println("..."); break; case "酸辣土豆絲": System.out.println("先放蔥姜蒜"); System.out.println("再放土豆絲"); System.out.println("..."); break; } System.out.println(dishName + "出鍋"); } }
廚師類,只負責了一項職責:做飯。
這就是類的單一職責原則。
Chef類只有一個cooking方法,cooking方法是根據(jù)下單的菜品名稱去烹飪不同的菜,以及炒西紅柿雞蛋以及酸辣土豆絲的具體烹飪過程。這樣做合適嗎?
不合適的,cooking方法應該只有菜品分發(fā)這一項職責,而炒西紅柿雞蛋以及酸辣土豆絲這兩件事顯然易見與分發(fā)沒有任何關(guān)系,所以拆分出來效果會更好。
我們將廚師類再優(yōu)化下。
package com.fanqiekt.principle.single; /** * 廚師 * * @author 番茄課堂-懶人 */ public class Chef { /** * 做飯 * 方法的單一職責原則 * @param dishName 下單的菜名 */ public void cooking(String dishName) { System.out.println("開始烹飪:"+dishName); switch (dishName){ case "西紅柿炒雞蛋": cookingTomato(); break; case "酸辣土豆絲": cookingPotato(); break; } System.out.println(dishName + "出鍋"); } /** * 炒西紅柿雞蛋 */ private void cookingTomato() { System.out.println("先炒雞蛋"); System.out.println("再炒西紅柿"); System.out.println("..."); } /** * 炒酸辣土豆絲 */ private void cookingPotato() { System.out.println("先放蔥姜蒜"); System.out.println("再放土豆絲"); System.out.println("..."); } }
優(yōu)化后Chef類有三個方法。
cooking方法是根據(jù)下單的菜品名稱去烹飪不同的菜。
cookingTomato方法是炒西紅柿雞蛋。
cookingPotato方法是炒酸辣土豆絲。
每個方法只負責一項職責,這就是方法的單一職責原則。
遵守方法單一職責原則的類,是不是更加的直觀?修改各自的方法是不是也沒有影響到其他的方法?
接下來,我們再優(yōu)化下Waiter類,讓他遵循類的單一職責原則。
package com.fanqiekt.principle.single; /** * 單一職責原則的服務(wù)員 * * @author 番茄課堂-懶人 */ public class Waiter { private Chef chef = new Chef(); /** * 點餐 * @param dishName 餐名 */ public void order(String dishName) { System.out.println("客人點餐:"+dishName); chef.cooking(dishName); System.out.println(dishName+"上桌啦,請您品嘗!"); } }
優(yōu)化后SingleWaiter類有只負責點餐、上餐這些與服務(wù)員相關(guān)的職責,而做飯的這些無關(guān)的職責則交給了Chef。
遵守類單一職責原則的項目,是不是更加的直觀?修改各自的類是不是也沒有影響到其他的類?
接下來,我們把Client運行一下。
客人點餐:西紅柿炒雞蛋 開始烹飪:西紅柿炒雞蛋 先炒雞蛋 再炒西紅柿 ... 西紅柿炒雞蛋出鍋 西紅柿炒雞蛋上桌啦,請您品嘗 ------- 客人點餐:酸辣土豆絲 開始烹飪:酸辣土豆絲 先放蔥姜蒜 再放土豆絲 ... 酸辣土豆絲出鍋 酸辣土豆絲上桌啦,請您品嘗
結(jié)果與原來一致。
4、優(yōu)點擼過代碼后,我們發(fā)現(xiàn)單一職責原則的幾個優(yōu)點。
提高類的可讀性
符合單一職責原則的方法、類,結(jié)構(gòu)會更加的清晰,類的可讀性也就提高了。
降低類的復雜性
一個類只負責一項職責,一個方法也只負責一項職責。肯定要比功能冗雜到一個方法,一個類中要簡單得多。
降低風險
修改其中的一個業(yè)務(wù),不會影響到業(yè)務(wù)。
5、總結(jié)我們必須要意識到,一味的遵守單一職責原則,不停的分拆類所付出的開銷是很大的。
這時候就涉及到平衡的問題,平衡單一職責原則與修改造成的開銷。
懶人的觀點是如果一個方法邏輯不復雜的情況下,可以修改方法實現(xiàn),否則要拆分為兩個方法,遵循方法級別的單一職責原則。
如果一個類方法不多的情況下,可以只增加方法,而不用分拆為多個類,否則要拆分為多個類,遵循類級別的單一職責原則。
6、嘻哈說接下來,請您欣賞單一職責原則的原創(chuàng)歌曲。
嘻哈說:單一職責原則 作曲:懶人 作詞:懶人 Rapper:懶人 周末約上了好友去熟悉的餐館聚餐 只負責點餐的漂亮服務(wù)員保持笑容已經(jīng)成為習慣 只負責做飯的帥氣廚師一直待在了煙霧彌漫了幾遍的廚房里面 每個人有自己負責的地盤 就像單一職責 一個類只有一個職責 好體面 它降低了類的復雜性 它提高了類的可讀性 那風險被降低代表著單一職責沒毛病
試聽請點擊這里
閑來無事聽聽曲,知識已填腦中去;
學習復習新方式,頭戴耳機不小覷。
番茄課堂,學習也要酷。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/77274.html
摘要:今天說一下,單一職責原則。比如,接口的地址本來已經(jīng)很完美了,但是你的是處女座最討厭處女座非要給路由添加幾個以保證后臺數(shù)據(jù)的安全。為了過年,我會選擇使用,因為不知道處女座以后會做出什么傻事來。此時的使用動態(tài)織入后,可以完美的解決處女座。 在設(shè)計模式中,有著幾條視為黃金原則,設(shè)計模式都是圍繞黃金原則,對代碼或者說是架構(gòu)設(shè)計做出一些相應的調(diào)整,久而久之,GoF 4人組,發(fā)現(xiàn)其實有些設(shè)計思想可...
摘要:,開始我們的第一篇單一職責。通過解耦可以讓每個職責工更加有彈性地變化。關(guān)于本文本文轉(zhuǎn)自大叔的深入理解系列。深入理解系列文章,包括了原創(chuàng),翻譯,轉(zhuǎn)載,整理等各類型文章,原文是大叔的一個非常不錯的專題,現(xiàn)將其重新整理發(fā)布。 前言 Bob大叔提出并發(fā)揚了S.O.L.I.D五大原則,用來更好地進行面向?qū)ο缶幊蹋宕笤瓌t分別是: The Single Responsibility Princi...
摘要:為什么要采用面向?qū)ο缶幊探鉀Q問題更容易設(shè)計計算機程序就是為了解決人類的問題。面向?qū)ο缶幊绦枰獙I(yè)務(wù)及代碼的架構(gòu)是有一定的要求的。 1. 編程方式 我們目前的編程方式大體可以有以下三種編程方式: 順序編程 過程式編程 面向?qū)ο缶幊? 在講面向?qū)ο缶幊虝r先講一下什么是順序編程,什么是過程式編程,什么是面向?qū)ο缶幊蹋? 順序編程: 就是只用一個單線程去執(zhí)行一段代碼,執(zhí)行過程根據(jù)代碼依次從上...
摘要:什么是代理模式代理模式,類似于明星的經(jīng)紀人,想要拜訪明星,需要先通過經(jīng)紀人的溝通。不同于裝飾器,那種動態(tài)加載一個對象,可以說在代理模式當中,代理是早已既定的。又稱單一功能原則,面向?qū)ο笪鍌€基本原則之一。 什么是代理模式 代理模式,類似于明星的經(jīng)紀人,想要拜訪明星,需要先通過經(jīng)紀人的溝通。而在JS當中,如果想訪問一個類,需要通過另一個類來間接訪問 。不同于裝飾器,那種動態(tài)加載一個對象,可...
閱讀 3018·2021-10-27 14:15
閱讀 3011·2021-09-07 10:18
閱讀 1328·2019-08-30 15:53
閱讀 1581·2019-08-26 18:18
閱讀 3382·2019-08-26 12:15
閱讀 3467·2019-08-26 10:43
閱讀 659·2019-08-23 16:43
閱讀 2216·2019-08-23 15:27