自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

面向?qū)ο笤O(shè)計(jì)原則之單一職責(zé)

開發(fā) 架構(gòu)
本文討論了面向?qū)ο笤O(shè)計(jì)(OOD)中的單一職責(zé)原則。單一職責(zé)簡(jiǎn)單來(lái)說(shuō)的意思就是:就一個(gè)類而言,應(yīng)該僅有一個(gè)引起它變化的原因。

大家都知道面向?qū)ο笫且环N編程思想,而面向?qū)ο笤O(shè)計(jì)(OOD)則可以說(shuō)是每位程序員都琢磨過(guò)的。所謂三人行必有我?guī)?,下面看看ohmygodlzl總結(jié)的一些OOD的心得體會(huì),其中著重講述了單一職責(zé)這一原則。

一直想跟同志們探討一下面向?qū)ο笤O(shè)計(jì)(OOD)的原則問(wèn)題,但因?yàn)樽约豪斫庥邢?,怕說(shuō)不好誤人子弟,一直就沒(méi)開始?,F(xiàn)在想做個(gè)嘗試,從淺處說(shuō)起,便于理解,也希望能對(duì)我們?nèi)粘5拈_發(fā)起到幫助。

我們做軟件開發(fā),要做的事情無(wú)非就是:拿到一份需求,通過(guò)一系列步驟把它轉(zhuǎn)化為可運(yùn)行的系統(tǒng)。這些步驟簡(jiǎn)單的說(shuō)就是需求分析――>面向?qū)ο蠓治觯òI(lǐng)域建模)――>架構(gòu)設(shè)計(jì)――>詳細(xì)設(shè)計(jì)――>編碼――>測(cè)試――>發(fā)布這樣的過(guò)程,其中架構(gòu)設(shè)計(jì)和詳細(xì)設(shè)計(jì)中都要用到OOD的一些原則。說(shuō)起面向?qū)ο?,一般大家都?huì)想到封裝,繼承,多態(tài),這是面向?qū)ο蟮奶卣?,還不是原則,我想說(shuō)的原則是Robert C. Martin在他的《敏捷軟件開發(fā)-原則模式和實(shí)踐》中提到的原則。今天聊聊單一職責(zé)原則(SRP)。

做開發(fā)到現(xiàn)在,相信大家已經(jīng)聽到過(guò)這樣的說(shuō)法:"類的職責(zé)越單一,越容易重用。"這話怎么理解呢?我舉個(gè)例子,校驗(yàn)碼。設(shè)想你現(xiàn)在拿到一個(gè)任務(wù)就是實(shí)現(xiàn)我們系統(tǒng)中的登錄模塊的校驗(yàn)碼功能,你怎么做?我覺(jué)得我們大部分開發(fā)人員都會(huì)做下面這樣的設(shè)計(jì)(當(dāng)然更壞的是有人干脆寫一個(gè)工具類,提供一個(gè)靜態(tài)的generateVerifyCode方法):

generateVerifyCode 

這個(gè)設(shè)計(jì)有什么問(wèn)題呢?有接口有實(shí)現(xiàn),貌似夠合理了。我們拿實(shí)際發(fā)生的事來(lái)看夠不夠合理――我們系統(tǒng)剛上線的時(shí)候校驗(yàn)碼的實(shí)現(xiàn)沒(méi)有現(xiàn)在這樣花哨,那個(gè)時(shí)候只是白色背景加上一組沒(méi)有經(jīng)過(guò)扭曲處理的數(shù)字;但是后來(lái)需求進(jìn)化了,因?yàn)樵瓉?lái)的校驗(yàn)碼可能會(huì)被破譯,所以需要對(duì)數(shù)字進(jìn)行扭曲,而且不能只產(chǎn)生數(shù)字,還要有字母,以增加破譯的難度。這時(shí)我們?cè)趺崔k?基于上面的設(shè)計(jì),就需要修改VerifyCodeGeneratorImpl類(注意:即使在這種不合理的設(shè)計(jì)下,修改實(shí)現(xiàn)也是不好的做法,倒不如丟棄這個(gè)實(shí)現(xiàn),新增一個(gè)實(shí)現(xiàn)),修改其中產(chǎn)生隨機(jī)數(shù)的代碼,并且在生成圖片的時(shí)候?qū)Ξa(chǎn)生的隨機(jī)文本添加扭曲處理邏輯。因?yàn)樾枨蟮淖兓薷拇a, 這說(shuō)明原來(lái)的設(shè)計(jì)是不好的,違反了面向?qū)ο笤O(shè)計(jì)的另外一個(gè)原則"開放封閉原則(OCP)",這個(gè)原則另外再談,主要就是說(shuō)一個(gè)類(或者模塊)只可以擴(kuò)展,但不可修改。

細(xì)分析可以看出,導(dǎo)致實(shí)現(xiàn)類需要做修改的原因是:它承擔(dān)了兩個(gè)本應(yīng)該分離的職責(zé)――產(chǎn)生隨機(jī)文本和生成校驗(yàn)碼圖片。好,我們嘗試將產(chǎn)生隨機(jī)文本的職責(zé)分離出來(lái),設(shè)計(jì)如下:

generateVerifyCode 

在這樣的設(shè)計(jì)下, 校驗(yàn)碼隨機(jī)文本的生成職責(zé)被分離成一個(gè)單獨(dú)的演化體系,隨著需求的變化可以添加產(chǎn)生漢字隨機(jī)文本之類的新實(shí)現(xiàn),并且不影響校驗(yàn)碼的顯示。但這個(gè)設(shè)計(jì)還沒(méi)有滿足需求的變更,因?yàn)楝F(xiàn)在的需求是不光隨機(jī)文本內(nèi)容從純數(shù)字變成了數(shù)字加字母,而且要求顯示的時(shí)候?qū)?shù)字進(jìn)行扭曲,在這個(gè)設(shè)計(jì)中,我們可以添加新的VerifyCodeGenerator實(shí)現(xiàn)如TransformedVerifyCodeGeneratorImpl以替換原來(lái)的VerifyCodeGeneratorImpl。這樣做可行,但還有更好點(diǎn)的設(shè)計(jì),如下:

generateVerifyCode 

這樣做,把圖片的生成職責(zé)也單獨(dú)抽象成一個(gè)演化體系,這樣以來(lái),將來(lái)如果需要在顯示校驗(yàn)碼時(shí)加上背景色或者背景噪音,只需要添加新的ImageGenerator實(shí)現(xiàn)。而且ImageGenerator作為一個(gè)通用的類,可以被其他有相應(yīng)生成圖片需求的類所重用而不是只局限于生成校驗(yàn)碼。上面的設(shè)計(jì)配合Spring的依賴注入,我們可以生成N * M種校驗(yàn)碼(N是RandomTextGenerator的實(shí)現(xiàn)類數(shù),M是ImageGenerator的實(shí)現(xiàn)類數(shù)),而基于最初的設(shè)計(jì),我們就需要?jiǎng)?chuàng)建N*M個(gè)VerifyCodeGenerator的實(shí)現(xiàn)類,且這些實(shí)現(xiàn)類可復(fù)用性很低。   

從上面例子的探討中可以得出這么一個(gè)結(jié)論:一個(gè)類(或者大到模塊,小到方法)承擔(dān)的職責(zé)越多,它被復(fù)用的可能性越小。這就是單一職責(zé)原則(SRP)要表述的內(nèi)容:就一個(gè)類而言,應(yīng)該僅有一個(gè)引起它變化的原因。    

本著這個(gè)原則,我們?cè)倏匆粋€(gè)常見的DAO設(shè)計(jì):

  1. interface DAO{  
  2.     Connection connect();  
  3.     void close();  
  4.     void executeUpdate();  
  5.     ResultSet executeQuery(String sql);  
  6. }  

這個(gè)接口有什么問(wèn)題沒(méi)有,好像很多人都這么干。只要設(shè)想一下如果底層數(shù)據(jù)庫(kù)變化了,connect方法的代碼就可能需要改變(有人說(shuō)我們不需要改變,那是因?yàn)槲覀兪褂昧薙pring提供的DataSource抽象隔離了取得數(shù)據(jù)庫(kù)鏈接的變化)。這個(gè)接口包含了兩個(gè)職責(zé):數(shù)據(jù)庫(kù)鏈接管理和數(shù)據(jù)操作。       

在實(shí)際操作中,如何識(shí)別職責(zé)是一個(gè)說(shuō)起來(lái)容易做起來(lái)難的問(wèn)題,比如有人可能會(huì)說(shuō),"產(chǎn)生校驗(yàn)碼圖片"本身就是一個(gè)獨(dú)立職責(zé)呀,我說(shuō)是的,如果我們的校驗(yàn)碼圖片一成不變,最初的那個(gè)設(shè)計(jì)不算很壞,只不過(guò)喪失了一點(diǎn)重用性而已(比如產(chǎn)生隨機(jī)文本的邏輯可能被其他的模塊重用),但是需求后來(lái)變化了,不能只顯示數(shù)字,還要字母,這說(shuō)明產(chǎn)生隨機(jī)文本是一個(gè)變化緯度,將來(lái)很可能還有新的變化,那就應(yīng)該把這個(gè)職責(zé)獨(dú)立出來(lái);需求又說(shuō)顯示的文本需要扭曲,這說(shuō)明圖片的生成也是一個(gè)變化緯度,沿著這個(gè)緯度將來(lái)很可能也有新的變化,那就也應(yīng)該把這個(gè)職責(zé)獨(dú)立出來(lái)。需求變化所影響的變化緯度,往往就是應(yīng)該被獨(dú)立的職責(zé)。所以如果你接到一個(gè)需求后發(fā)現(xiàn)需要修改一個(gè)已經(jīng)存在的類,那就要考慮一下是不是原來(lái)的設(shè)計(jì)不合理,沒(méi)有把應(yīng)該獨(dú)立出來(lái)的職責(zé)分離出來(lái)。需求變化結(jié)合經(jīng)驗(yàn)、常識(shí),就可以慢慢識(shí)別職責(zé)應(yīng)該分到什么粒度了。       

單一職責(zé)原則不光對(duì)類設(shè)計(jì)有意義,對(duì)以模塊、子系統(tǒng)為單位的架構(gòu)設(shè)計(jì)一樣有意義,一個(gè)模塊、子系統(tǒng)也應(yīng)該僅有一個(gè)引起它變化的原因,不同的是模塊和子系統(tǒng)承擔(dān)的職責(zé)粒度跟類相比是另外一個(gè)層次了。       

如果讓我列舉一下一個(gè)良好的設(shè)計(jì)應(yīng)該具備的素質(zhì),我會(huì)說(shuō):高內(nèi)聚,低耦合。單一職責(zé)原則正是實(shí)現(xiàn)高內(nèi)聚低耦合需要遵守的一個(gè)原則。

對(duì)于面向?qū)ο笤O(shè)計(jì),你有什么新的想法么?

【編輯推薦】

  1. PHP+Java的開發(fā)經(jīng)驗(yàn):不要太面向?qū)ο?/FONT>
  2. 全面介紹C#面向?qū)ο蟮确矫?/FONT>
  3. Jython中的對(duì)象——面向?qū)ο蟮恼Z(yǔ)言概述
  4. Scala簡(jiǎn)介:面向?qū)ο蠛秃瘮?shù)式編程的組合
  5. 61條Java面向?qū)ο笤O(shè)計(jì)的經(jīng)驗(yàn)原則
責(zé)任編輯:yangsai 來(lái)源: JavaEye博客
相關(guān)推薦

2012-03-08 10:57:00

Java設(shè)計(jì)模式

2013-04-17 10:46:54

面向?qū)ο?/a>

2012-06-07 10:11:01

面向?qū)ο?/a>設(shè)計(jì)原則Java

2024-05-10 09:28:57

Python面向?qū)ο?/a>代碼

2012-05-08 10:14:45

設(shè)計(jì)原則

2009-01-16 08:52:26

面向?qū)ο?/a>OOP編程

2009-06-30 15:29:00

Java面向?qū)ο?/a>

2011-07-12 17:53:21

PHP

2024-07-12 09:00:00

2023-12-08 07:59:41

對(duì)象設(shè)計(jì)設(shè)計(jì)模式軟件設(shè)計(jì)

2019-09-18 18:56:34

JavascriptOOP前端

2022-09-28 07:31:03

SOLID對(duì)象設(shè)計(jì)

2018-05-03 15:54:19

2015-03-16 11:14:26

Java程序員面向?qū)ο?/a>程序員

2011-07-05 15:22:04

程序設(shè)計(jì)

2012-03-13 09:24:30

Java

2013-01-08 10:06:43

創(chuàng)業(yè)創(chuàng)業(yè)方法

2015-10-29 09:30:38

程序員面向?qū)ο?/a>設(shè)計(jì)

2010-07-15 13:56:24

面向?qū)ο?/a>面向過(guò)程

2020-10-10 11:03:24

面向?qū)ο?/a>編程語(yǔ)言開發(fā)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)