這篇文章給大家介紹Java中設(shè)計(jì)模式有哪些原則,內(nèi)容非常詳細(xì),感興趣的小伙伴們可以參考借鑒,希望對(duì)大家能有所幫助。
創(chuàng)新互聯(lián)是專業(yè)的荔城網(wǎng)站建設(shè)公司,荔城接單;提供做網(wǎng)站、網(wǎng)站建設(shè),網(wǎng)頁設(shè)計(jì),網(wǎng)站設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行荔城網(wǎng)站開發(fā)網(wǎng)頁制作和功能擴(kuò)展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來合作!
一.單一職責(zé)原則
單一職責(zé)原則是最簡(jiǎn)單的面向?qū)ο笤O(shè)計(jì)原則,它用于控制類的粒度大小。單一職責(zé)原則定義如下:
單一職責(zé)原則(Single Responsibility Principle, SRP):一個(gè)類只負(fù)責(zé)一個(gè)功能領(lǐng)域中的相應(yīng)職責(zé),或者可以定義為:就一個(gè)類而言,應(yīng)該只有一個(gè)引起它變化的原因。
單一職責(zé)原則告訴我們:一個(gè)類不能太“累”!在軟件系統(tǒng)中,一個(gè)類(大到模塊,小到方法)承擔(dān)的職責(zé)越多,它被復(fù)用的可能性就越小,而且一個(gè)類承擔(dān)的職責(zé)過多,就相當(dāng)于將這些職責(zé)耦合在一起,當(dāng)其中一個(gè)職責(zé)變化時(shí),可能會(huì)影響其他職責(zé)的運(yùn)作,因此要將這些職責(zé)進(jìn)行分離,將不同的職責(zé)封裝在不同的類中,即將不同的變化原因封裝在不同的類中,如果多個(gè)職責(zé)總是同時(shí)發(fā)生改變則可將它們封裝在同一類中。
單一職責(zé)原則是實(shí)現(xiàn)高內(nèi)聚、低耦合的指導(dǎo)方針,它是最簡(jiǎn)單但又最難運(yùn)用的原則,需要設(shè)計(jì)人員發(fā)現(xiàn)類的不同職責(zé)并將其分離,而發(fā)現(xiàn)類的多重職責(zé)需要設(shè)計(jì)人員具有較強(qiáng)的分析設(shè)計(jì)能力和相關(guān)實(shí)踐經(jīng)驗(yàn)。
下面通過一個(gè)簡(jiǎn)單實(shí)例來進(jìn)一步分析單一職責(zé)原則:
Sunny軟件公司開發(fā)人員針對(duì)某CRM(Customer Relationship Management,客戶關(guān)系管理)系統(tǒng)中客戶信息圖形統(tǒng)計(jì)模塊提出了如圖1所示初始設(shè)計(jì)方案:
圖1 初始設(shè)計(jì)方案結(jié)構(gòu)圖
在圖1中,CustomerDataChart類中的方法說明如下:getConnection()方法用于連接數(shù)據(jù)庫,findCustomers()用于查詢所有的客戶信息,createChart()用于創(chuàng)建圖表,displayChart()用于顯示圖表。
現(xiàn)使用單一職責(zé)原則對(duì)其進(jìn)行重構(gòu)。
在圖1中,CustomerDataChart類承擔(dān)了太多的職責(zé),既包含與數(shù)據(jù)庫相關(guān)的方法,又包含與圖表生成和顯示相關(guān)的方法。如果在其他類中也需要連接數(shù)據(jù)庫或者使用findCustomers()方法查詢客戶信息,則難以實(shí)現(xiàn)代碼的重用。無論是修改數(shù)據(jù)庫連接方式還是修改圖表顯示方式都需要修改該類,它不止一個(gè)引起它變化的原因,違背了單一職責(zé)原則。因此需要對(duì)該類進(jìn)行拆分,使其滿足單一職責(zé)原則,類CustomerDataChart可拆分為如下三個(gè)類:
(1) DBUtil:負(fù)責(zé)連接數(shù)據(jù)庫,包含數(shù)據(jù)庫連接方法getConnection();
(2) CustomerDAO:負(fù)責(zé)操作數(shù)據(jù)庫中的Customer表,包含對(duì)Customer表的增刪改查等方法,如findCustomers();
(3) CustomerDataChart:負(fù)責(zé)圖表的生成和顯示,包含方法createChart()和displayChart()。
使用單一職責(zé)原則重構(gòu)后的結(jié)構(gòu)如圖2所示:
圖1原始結(jié)構(gòu)圖
在對(duì)系統(tǒng)進(jìn)行進(jìn)一步分析后發(fā)現(xiàn),無論是普通客戶還是VIP客戶,發(fā)送郵件的過程都是相同的,也就是說兩個(gè)send()方法中的代碼重復(fù),而且在本系統(tǒng)中還將增加新類型的客戶。為了讓系統(tǒng)具有更好的擴(kuò)展性,同時(shí)減少代碼重復(fù),使用里氏代換原則對(duì)其進(jìn)行重構(gòu)。
在本實(shí)例中,可以考慮增加一個(gè)新的抽象客戶類Customer,而將CommonCustomer和VIPCustomer類作為其子類,郵件發(fā)送類EmailSender類針對(duì)抽象客戶類Customer編程,根據(jù)里氏代換原則,能夠接受基類對(duì)象的地方必然能夠接受子類對(duì)象,因此將EmailSender中的send()方法的參數(shù)類型改為Customer,如果需要增加新類型的客戶,只需將其作為Customer類的子類即可。重構(gòu)后的結(jié)構(gòu)如圖2所示:
圖2 重構(gòu)后的結(jié)構(gòu)圖
四、依賴倒置原則
定義:高層模塊不應(yīng)該依賴低層模塊,二者都應(yīng)該依賴其抽象;抽象不應(yīng)該依賴細(xì)節(jié);細(xì)節(jié)應(yīng)該依賴抽象。即針對(duì)接口編程,不要針對(duì)實(shí)現(xiàn)編程
依賴倒轉(zhuǎn)其實(shí)就是誰也不要依靠誰,除了約定的接口,大家都可以靈活自如。依賴倒轉(zhuǎn)可以說是面向?qū)ο笤O(shè)計(jì)的標(biāo)志,用哪種語言來編寫程序不重要,如果編寫時(shí)考慮的都是如何針對(duì)抽象編程而不是針對(duì)細(xì)節(jié)編程,即程序中所有的依賴關(guān)系都是終止于抽象類或者接口,那就是面向?qū)ο蟮脑O(shè)計(jì),反之那就是過程化的設(shè)計(jì)了。如果設(shè)計(jì)的各個(gè)部件或類相互依賴,這樣就是耦合度高,難以維護(hù)和擴(kuò)展,這也就體現(xiàn)不出面向?qū)ο蟮暮锰幜恕?br/> 依賴倒轉(zhuǎn)原則,好比一個(gè)團(tuán)隊(duì),有需求組,開發(fā)組,測(cè)試組,開發(fā)組和測(cè)試組都是面對(duì)同樣的需求后,做自己相應(yīng)的工作,而不應(yīng)該是測(cè)試組按照開發(fā)組理解的需求去做測(cè)試用例,也就是說開發(fā)組和測(cè)試組都是直接面向需求組工作,大家的目的是一樣的,保證產(chǎn)品按時(shí)上線,需求是不依賴于開發(fā)和測(cè)試的。
依賴倒置原則基于這樣一個(gè)事實(shí):相對(duì)于細(xì)節(jié)的多變性,抽象的東西要穩(wěn)定的多。以抽象為基礎(chǔ)搭建起來的架構(gòu)比以細(xì)節(jié)為基礎(chǔ)搭建起來的架構(gòu)要穩(wěn)定的多。在java中,抽象指的是接口或者抽象類,細(xì)節(jié)就是具體的實(shí)現(xiàn)類,使用接口或者抽象類的目的是制定好規(guī)范和契約,而不去涉及任何具體的操作,把展現(xiàn)細(xì)節(jié)的任務(wù)交給他們的實(shí)現(xiàn)類去完成。
依賴倒置原則的中心思想是面向接口編程,傳遞依賴關(guān)系有三種方式,以上的說的是是接口傳遞,另外還有兩種傳遞方式:構(gòu)造方法傳遞和setter方法傳遞,相信用過Spring框架的,對(duì)依賴的傳遞方式一定不會(huì)陌生。
在實(shí)際編程中,我們一般需要做到如下3點(diǎn):
低層模塊盡量都要有抽象類或接口,或者兩者都有。
變量的聲明類型盡量是抽象類或接口。
使用繼承時(shí)遵循里氏替換原則。
總之,依賴倒置原則就是要我們面向接口編程,理解了面向接口編程,也就理解了依賴倒置。
五、接口隔離原則(Interface Segregation Principle)
接口隔離原則的含義是:建立單一接口,不要建立龐大臃腫的接口,盡量細(xì)化接口,接口中的方法盡量少。也就是說,我們要為各個(gè)類建立專用的接口,而不要試圖去建立一個(gè)很龐大的接口供所有依賴它的類去調(diào)用。在程序設(shè)計(jì)中,依賴幾個(gè)專用的接口要比依賴一個(gè)綜合的接口更靈活。接口是設(shè)計(jì)時(shí)對(duì)外部設(shè)定的“契約”,通過分散定義多個(gè)接口,可以預(yù)防外來變更的擴(kuò)散,提高系統(tǒng)的靈活性和可維護(hù)性。
說到這里,很多人會(huì)覺的接口隔離原則跟單一職責(zé)原則很相似,其實(shí)不然。其一,單一職責(zé)原則原注重的是職責(zé);而接口隔離原則注重對(duì)接口依賴的隔離。其二,單一職責(zé)原則主要是約束類,其次才是接口和方法,它針對(duì)的是程序中的實(shí)現(xiàn)和細(xì)節(jié);而接口隔離原則主要約束接口接口,主要針對(duì)抽象,針對(duì)程序整體框架的構(gòu)建。
采用接口隔離原則對(duì)接口進(jìn)行約束時(shí),要注意以下幾點(diǎn):
1. 接口盡量小,但是要有限度。對(duì)接口進(jìn)行細(xì)化可以提高程序設(shè)計(jì)靈活性是不掙的事實(shí),但是如果過小,則會(huì)造成接口數(shù)量過多,使設(shè)計(jì)復(fù)雜化。所以一定要適度。
2. 為依賴接口的類定制服務(wù),只暴露給調(diào)用的類它需要的方法,它不需要的方法則隱藏起來。只有專注地為一個(gè)模塊提供定制服務(wù),才能建立最小的依賴關(guān)系。
3. 提高內(nèi)聚,減少對(duì)外交互。使接口用最少的方法去完成最多的事情。
運(yùn)用接口隔離原則,一定要適度,接口設(shè)計(jì)的過大或過小都不好。設(shè)計(jì)接口的時(shí)候,只有多花些時(shí)間去思考和籌劃,才能準(zhǔn)確地實(shí)踐這一原則。
Sunny軟件公司開發(fā)人員針對(duì)某CRM系統(tǒng)的客戶數(shù)據(jù)顯示模塊設(shè)計(jì)了如圖1所示接口,其中方法dataRead()用于從文件中讀取數(shù)據(jù),方法transformToXML()用于將數(shù)據(jù)轉(zhuǎn)換成XML格式,方法createChart()用于創(chuàng)建圖表,方法displayChart()用于顯示圖表,方法createReport()用于創(chuàng)建文字報(bào)表,方法displayReport()用于顯示文字報(bào)表。 圖1 初始設(shè)計(jì)方案結(jié)構(gòu)圖 在實(shí)際使用過程中發(fā)現(xiàn)該接口很不靈活,例如如果一個(gè)具體的數(shù)據(jù)顯示類無須進(jìn)行數(shù)據(jù)轉(zhuǎn)換(源文件本身就是XML格式),但由于實(shí)現(xiàn)了該接口,將不得不實(shí)現(xiàn)其中聲明的transformToXML()方法(至少需要提供一個(gè)空實(shí)現(xiàn));如果需要?jiǎng)?chuàng)建和顯示圖表,除了需實(shí)現(xiàn)與圖表相關(guān)的方法外,還需要實(shí)現(xiàn)創(chuàng)建和顯示文字報(bào)表的方法,否則程序編譯時(shí)將報(bào)錯(cuò)。 現(xiàn)使用接口隔離原則對(duì)其進(jìn)行重構(gòu)。 |
在圖1中,由于在接口CustomerDataDisplay中定義了太多方法,即該接口承擔(dān)了太多職責(zé),一方面導(dǎo)致該接口的實(shí)現(xiàn)類很龐大,在不同的實(shí)現(xiàn)類中都不得不實(shí)現(xiàn)接口中定義的所有方法,靈活性較差,如果出現(xiàn)大量的空方法,將導(dǎo)致系統(tǒng)中產(chǎn)生大量的無用代碼,影響代碼質(zhì)量;另一方面由于客戶端針對(duì)大接口編程,將在一定程序上破壞程序的封裝性,客戶端看到了不應(yīng)該看到的方法,沒有為客戶端定制接口。因此需要將該接口按照接口隔離原則和單一職責(zé)原則進(jìn)行重構(gòu),將其中的一些方法封裝在不同的小接口中,確保每一個(gè)接口使用起來都較為方便,并都承擔(dān)某一單一角色,每個(gè)接口中只包含一個(gè)客戶端(如模塊或類)所需的方法即可。
通過使用接口隔離原則,本實(shí)例重構(gòu)后的結(jié)構(gòu)如圖2所示:
圖2 重構(gòu)后的結(jié)構(gòu)圖
六、迪米特法則(Law Of Demeter)
迪米特法則其根本思想,是強(qiáng)調(diào)了類之間的松耦合,類之間的耦合越弱,越有利于復(fù)用,一個(gè)處在弱耦合的類被修改,不會(huì)對(duì)有關(guān)系的類造成影響,也就是說,信息的隱藏促進(jìn)了軟件的復(fù)用。
迪米特法則要求我們?cè)谠O(shè)計(jì)系統(tǒng)時(shí),應(yīng)該盡量減少對(duì)象之間的交互,如果兩個(gè)對(duì)象之間不必彼此直接通信,那么這兩個(gè)對(duì)象就不應(yīng)當(dāng)發(fā)生任何直接的相互作用,如果其中的一個(gè)對(duì)象需要調(diào)用另一個(gè)對(duì)象的某一個(gè)方法的話,可以通過第三者轉(zhuǎn)發(fā)這個(gè)調(diào)用。簡(jiǎn)言之,就是通過引入一個(gè)合理的第三者來降低現(xiàn)有對(duì)象之間的耦合度。
在將迪米特法則運(yùn)用到系統(tǒng)設(shè)計(jì)中時(shí),要注意下面的幾點(diǎn):在類的劃分上,應(yīng)當(dāng)盡量創(chuàng)建松耦合的類,類之間的耦合度越低,就越有利于復(fù)用,一個(gè)處在松耦合中的類一旦被修改,不會(huì)對(duì)關(guān)聯(lián)的類造成太大波及;在類的結(jié)構(gòu)設(shè)計(jì)上,每一個(gè)類都應(yīng)當(dāng)盡量降低其成員變量和成員函數(shù)的訪問權(quán)限;在類的設(shè)計(jì)上,只要有可能,一個(gè)類型應(yīng)當(dāng)設(shè)計(jì)成不變類;在對(duì)其他類的引用上,一個(gè)對(duì)象對(duì)其他對(duì)象的引用應(yīng)當(dāng)降到最低。
下面通過一個(gè)簡(jiǎn)單實(shí)例來加深對(duì)迪米特法則的理解:
Sunny軟件公司所開發(fā)CRM系統(tǒng)包含很多業(yè)務(wù)操作窗口,在這些窗口中,某些界面控件之間存在復(fù)雜的交互關(guān)系,一個(gè)控件事件的觸發(fā)將導(dǎo)致多個(gè)其他界面控件產(chǎn)生響應(yīng),例如,當(dāng)一個(gè)按鈕(Button)被單擊時(shí),對(duì)應(yīng)的列表框(List)、組合框(ComboBox)、文本框(TextBox)、文本標(biāo)簽(Label)等都將發(fā)生改變,在初始設(shè)計(jì)方案中,界面控件之間的交互關(guān)系可簡(jiǎn)化為如圖1所示結(jié)構(gòu): 圖1 初始設(shè)計(jì)方案結(jié)構(gòu)圖 在圖1中,由于界面控件之間的交互關(guān)系復(fù)雜,導(dǎo)致在該窗口中增加新的界面控件時(shí)需要修改與之交互的其他控件的源代碼,系統(tǒng)擴(kuò)展性較差,也不便于增加和刪除新控件。 現(xiàn)使用迪米特對(duì)其進(jìn)行重構(gòu)。 |
關(guān)于Java中設(shè)計(jì)模式有哪些原則就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到。