一痹兜、Spring中常用的設(shè)計(jì)模式
1穆咐、我們通常說(shuō)的23種經(jīng)典設(shè)計(jì)模式可以通過(guò)下表一目了然:
通常來(lái)說(shuō),設(shè)計(jì)模式都是混合使用字旭,不會(huì)獨(dú)立應(yīng)用对湃。利用窮舉法充分理解設(shè)計(jì)模式的應(yīng)用場(chǎng)景。在平時(shí)的應(yīng)用中遗淳,不是用設(shè)計(jì)模式去生搬硬套拍柒,而是根據(jù)具體業(yè)務(wù)問(wèn)題需要時(shí)借鑒。
2屈暗、設(shè)計(jì)模式在應(yīng)用中遵循六大原則:
a拆讯、開(kāi)閉原則(OpenClosePrinciple)
開(kāi)閉原則就是說(shuō)對(duì)擴(kuò)展開(kāi)放,對(duì)修改關(guān)閉养叛。在程序需要進(jìn)行拓展的時(shí)候种呐,不能去修改原有的代碼,實(shí)現(xiàn)
一個(gè)熱插拔的效果弃甥。所以一句話概括就是:為了使程序的擴(kuò)展性好爽室,易于維護(hù)和升級(jí)。想要達(dá)到這樣的
效果淆攻,我們需要使用接口和抽象類(lèi)阔墩,后面的具體設(shè)計(jì)中我們會(huì)提到這點(diǎn)。
b瓶珊、里氏代換原則(LiskovSubstitutionPrinciple)
面向?qū)ο笤O(shè)計(jì)的基本原則之一戈擒。里氏代換原則中說(shuō),任何基類(lèi)可以出現(xiàn)的地方艰毒,子類(lèi)一定可以出現(xiàn)筐高。LSP是繼承復(fù)用的基石,只有當(dāng)衍生類(lèi)可以替換掉基類(lèi)丑瞧,軟件單位的功能不受到影響時(shí)柑土,基類(lèi)才能真正被復(fù)用,而衍生類(lèi)也能夠在基類(lèi)的基礎(chǔ)上增加新的行為绊汹。里氏代換原則是對(duì)“開(kāi)-閉”原則的補(bǔ)充稽屏。實(shí)現(xiàn)“開(kāi)-閉”原則的關(guān)鍵步驟就是抽象化。而基類(lèi)與子類(lèi)的繼承關(guān)系就是抽象化的具體實(shí)現(xiàn)西乖,所以里氏代換原則是對(duì)實(shí)現(xiàn)抽象化的具體步驟的規(guī)范狐榔。
c坛增、依賴(lài)倒轉(zhuǎn)原則(DependenceInversionPrinciple)
這個(gè)是開(kāi)閉原則的基礎(chǔ),具體內(nèi)容:針對(duì)接口編程薄腻,依賴(lài)于抽象而不依賴(lài)于具體收捣。
d、接口隔離原則(InterfaceSegregationPrinciple)
這個(gè)原則的意思是:使用多個(gè)隔離的接口庵楷,比使用單個(gè)接口要好罢艾。還是一個(gè)降低類(lèi)之間的耦合度的意思,從這兒我們看出尽纽,其實(shí)設(shè)計(jì)模式就是一個(gè)軟件的設(shè)計(jì)思想咐蚯,從大型軟件架構(gòu)出發(fā),為了升級(jí)和維護(hù)方便弄贿。所以上文中多次出現(xiàn):降低依賴(lài)春锋,降低耦合。
e差凹、迪米特法則(最少知道原則)(DemeterPrinciple)
為什么叫最少知道原則期奔,就是說(shuō):一個(gè)實(shí)體應(yīng)當(dāng)盡量少的與其他實(shí)體之間發(fā)生相互作用,使得系統(tǒng)功能模塊相對(duì)獨(dú)立直奋。
f、合成復(fù)用原則(CompositeReusePrinciple)
原則是盡量使用合成/聚合的方式施禾,而不是使用繼承脚线。
設(shè)計(jì)模式之間的關(guān)系圖:
二:Spring中常用的設(shè)計(jì)模式:
1.1、簡(jiǎn)單工廠模式(Factory)
應(yīng)用場(chǎng)景:又叫做靜態(tài)工廠方法(StaticFactoryMethod)模式弥搞,但不屬于23種設(shè)計(jì)模式之一邮绿。簡(jiǎn)單工廠模式的實(shí)質(zhì)是由一個(gè)工廠類(lèi)根據(jù)傳入的參數(shù),動(dòng)態(tài)決定應(yīng)該創(chuàng)建哪一個(gè)產(chǎn)品類(lèi)攀例。
Spring中的BeanFactory就是簡(jiǎn)單工廠模式的體現(xiàn)船逮,根據(jù)傳入一個(gè)唯一的標(biāo)識(shí)來(lái)獲得Bean對(duì)象,但是否是在傳入?yún)?shù)后創(chuàng)建還是傳入?yún)?shù)前創(chuàng)建這個(gè)要根據(jù)具體情況來(lái)定粤铭。
1.2挖胃、工廠方法模式(FactoryMethod)
應(yīng)用場(chǎng)景:通常由應(yīng)用程序直接使用new創(chuàng)建新的對(duì)象,為了將對(duì)象的創(chuàng)建和使用相分離梆惯,采用工廠模式,即應(yīng)用程序?qū)?duì)象的創(chuàng)建及初始化職責(zé)交給工廠對(duì)象酱鸭。
一般情況下,應(yīng)用程序有自己的工廠對(duì)象來(lái)創(chuàng)建Bean.如果將應(yīng)用程序自己的工廠對(duì)象交給Spring管理,那么Spring
管理的就不是普通的Bean,而是工廠Bean。
1.3垛吗、單例模式(Singleton)
應(yīng)用場(chǎng)景:保證一個(gè)類(lèi)僅有一個(gè)實(shí)例凹髓,并提供一個(gè)訪問(wèn)它的全局訪問(wèn)點(diǎn)。
Spring中的單例模式完成了后半句話怯屉,即提供了全局的訪問(wèn)點(diǎn)BeanFactory蔚舀。但沒(méi)有從構(gòu)造器級(jí)別去控制單例饵沧,這是因?yàn)镾pring管理的是是任意的Java對(duì)象。Spring下默認(rèn)的Bean均為單例赌躺。
1.4、原型模式(Prototype)
應(yīng)用場(chǎng)景:原型模式就是從一個(gè)對(duì)象再創(chuàng)建另外一個(gè)可定制的對(duì)象讶泰,而且不需要知道任何創(chuàng)建的細(xì)節(jié)咏瑟。
所謂原型模式,就是Java中的克隆技術(shù)痪署,以某個(gè)對(duì)象為原型码泞。復(fù)制出新的對(duì)象。顯然新的對(duì)象具備原型對(duì)象的特點(diǎn)狼犯,效率高(避免了重新執(zhí)行構(gòu)造過(guò)程步驟)余寥。
1.5、代理模式(Proxy)
應(yīng)用場(chǎng)景:為其他對(duì)象提供一種代理以控制對(duì)這個(gè)對(duì)象的訪問(wèn)悯森。從結(jié)構(gòu)上來(lái)看和Decorator模式類(lèi)似宋舷,但Proxy是控制,更像是一種對(duì)功能的限制瓢姻,而Decorator是增加職責(zé)祝蝠。
Spring的Proxy模式在AOP中有體現(xiàn),比如JdkDynamicAopProxy和Cglib2AopProxy幻碱。
1.6绎狭、策略模式(Strategy)
應(yīng)用場(chǎng)景:定義一系列的算法,把它們一個(gè)個(gè)封裝起來(lái)褥傍,并且使它們可相互替換儡嘶。本模式使得算法可獨(dú)
立于使用它的客戶而變化。
Spring中在實(shí)例化對(duì)象的時(shí)候用到Strategy模式恍风,在SimpleInstantiationStrategy有使用蹦狂。
1.7、模板方法模式(TemplateMethod)
定義一個(gè)操作中的算法的骨架朋贬,而將一些步驟延遲到子類(lèi)中鸥咖。TemplateMethod使得子類(lèi)可以不改變一個(gè)算法的結(jié)構(gòu)即可重定義該算法的某些特定步驟。
TemplateMethod模式一般是需要繼承的兄世。這里想要探討另一種對(duì)TemplateMethod的理解啼辣。Spring中的JdbcTemplate,在用這個(gè)類(lèi)時(shí)并不想去繼承這個(gè)類(lèi)御滩,因?yàn)檫@個(gè)類(lèi)的方法太多鸥拧,但是我們還是想用到JdbcTemplate
已有的穩(wěn)定的党远、公用的數(shù)據(jù)庫(kù)連接,那么我們?cè)趺崔k呢富弦?我們可以把變化的東西抽出來(lái)作為一個(gè)參數(shù)傳入JdbcTemplate的方法中沟娱。但是變化的東西是一段代碼,而且這段代碼會(huì)用到JdbcTemplate中的變量腕柜。怎么辦济似?那我們就用回調(diào)對(duì)象吧。在這個(gè)回調(diào)對(duì)象中定義一個(gè)操縱JdbcTemplate中變量的方法盏缤,我們?nèi)?shí)現(xiàn)這個(gè)方法砰蠢,就把變化的東西集中到這里了。然后我們?cè)賯魅脒@個(gè)回調(diào)對(duì)象到JdbcTemplate唉铜,從而完成了調(diào)用台舱。這就是TemplateMethod不需要繼承的另一種實(shí)現(xiàn)方式。
1.8潭流、委派模式(Delegate)
應(yīng)用場(chǎng)景:不屬于23種設(shè)計(jì)模式之一竞惋,是面向?qū)ο笤O(shè)計(jì)模式中常用的一種模式。這種模式的原理為類(lèi)B和類(lèi)A是兩個(gè)互相沒(méi)有任何關(guān)系的類(lèi)灰嫉,B具有和A一模一樣的方法和屬性拆宛;并且調(diào)用B中的方法,屬性就是調(diào)用A中同名的方法和屬性讼撒。B好像就是一個(gè)受A授權(quán)委托的中介浑厚。第三方的代碼不需要知道A的存在,也不需要和A發(fā)生直接的聯(lián)系椿肩,通過(guò)B就可以直接使用A的功能瞻颂,這樣既能夠使用到A的各種功能豺谈,又能夠很好的將A保護(hù)起來(lái)了郑象,一舉兩得。
1.9茬末、適配器模式(Adapter)
SpringAOP模塊對(duì)BeforeAdvice厂榛、AfterAdvice、ThrowsAdvice三種通知類(lèi)型的支持實(shí)際上是借助適配器模式來(lái)實(shí)現(xiàn)的丽惭,這樣的好處是使得框架允許用戶向框架中加入自己想要支持的任何一種通知類(lèi)型击奶,上述三種通知類(lèi)型是SpringAOP模塊定義的,它們是AOP聯(lián)盟定義的Advice的子類(lèi)型责掏。
1.10柜砾、裝飾器模式(Decorator)
應(yīng)用場(chǎng)景:在我們的項(xiàng)目中遇到這樣一個(gè)問(wèn)題:我們的項(xiàng)目需要連接多個(gè)數(shù)據(jù)庫(kù),而且不同的客戶在每
次訪問(wèn)中根據(jù)需要會(huì)去訪問(wèn)不同的數(shù)據(jù)庫(kù)换衬。我們以往在Spring和Hibernate框架中總是配置一個(gè)數(shù)據(jù)源痰驱,因而SessionFactory的DataSource屬性總是指向這個(gè)數(shù)據(jù)源并且恒定不變证芭,所有DAO在使用SessionFactory的時(shí)候都是通過(guò)這個(gè)數(shù)據(jù)源訪問(wèn)數(shù)據(jù)庫(kù)。但是現(xiàn)在担映,由于項(xiàng)目的需要废士,我們的DAO在訪問(wèn)SessionFactory的時(shí)候都不得不在多個(gè)數(shù)據(jù)源中不斷切換,問(wèn)題就出現(xiàn)了:如何讓SessionFactory在執(zhí)行數(shù)據(jù)持久化的時(shí)候蝇完,根據(jù)客戶的需求能夠動(dòng)態(tài)切換不同的數(shù)據(jù)源官硝?我們能不能在Spring的框架下通過(guò)少量修改得到解決?是否有什么設(shè)計(jì)模式可以利用呢短蜕?
首先想到在Spring的ApplicationContext中配置所有的DataSource氢架。這些DataSource可能是各種不同類(lèi)型的,比如不同的數(shù)據(jù)庫(kù):Oracle忿危、SQLServer达箍、MySQL等,也可能是不同的數(shù)據(jù)源:比如Apache提供的org.apache.commons.dbcp.BasicDataSource铺厨、Spring提供的org.springframework.jndi.JndiObjectFactoryBean等缎玫。然后SessionFactory根據(jù)客戶的每次請(qǐng)求,將DataSource屬性設(shè)置成不同的數(shù)據(jù)源解滓,以到達(dá)切換數(shù)據(jù)源的目的赃磨。
Spring中用到的包裝器模式在類(lèi)名上有兩種表現(xiàn):一種是類(lèi)名中含有Wrapper,另一種是類(lèi)名中含有Decorator洼裤×诨裕基本上都是動(dòng)態(tài)地給一個(gè)對(duì)象添加一些額外的職責(zé)。
1.11腮鞍、觀察者模式(Observer)
應(yīng)用場(chǎng)景:定義對(duì)象間的一種一對(duì)多的依賴(lài)關(guān)系值骇,當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變時(shí),所有依賴(lài)于它的對(duì)象
都得到通知并被自動(dòng)更新移国。
Spring中Observer模式常用的地方是Listener的實(shí)現(xiàn)吱瘩。如ApplicationListener。