吳雨桐
(四川大學(xué)錦城學(xué)院 計算機(jī)與軟件學(xué)院,四川 成都 611731)
設(shè)計模式是一套可以被反復(fù)使用、程序員熟知的、經(jīng)過分類編目的代碼設(shè)計經(jīng)驗的一種總結(jié)。使用設(shè)計模式主要是為了可重用代碼、讓代碼更容易被他人理解、保證代碼的可靠性。毫無疑問,設(shè)計模式無論是于人于己還是對于程序來講都是多贏的,設(shè)計模式使代碼編制真正工程化,就像軟件工程的基石,和大廈的一塊塊磚石一樣。設(shè)計模式分為創(chuàng)建模式、結(jié)構(gòu)模式和行為模式三大類。其中創(chuàng)建模式一般對于對象的實例創(chuàng)建比較有用。結(jié)構(gòu)模式通過處理對象和類之間的組合來作用于企業(yè)級開發(fā)應(yīng)用的設(shè)計結(jié)構(gòu),以達(dá)到降低項目開發(fā)的復(fù)雜度,提高其系統(tǒng)的可復(fù)用性和性能。行為模式是作用域一組對象之間的交互作用。
Spring 是編程領(lǐng)域的一個輕量級開源框架,被廣大java 工程師所熟知。該框架在 2002 年最早提出并隨后創(chuàng)建,是為了解決企業(yè)級編程開發(fā)的復(fù)雜性,實現(xiàn)快捷開發(fā)的應(yīng)用型框架 。Spring 是一個開源容器框架,集成各類型的工具,通過核心的Bean Factory 實現(xiàn)了底層的類的實例化和生命周期的管理。在整個框架中,各類型的功能被抽象成一個個的 Bean,這樣就可以實現(xiàn)各種功能的管理,包括動態(tài)加載和切面編程。當(dāng)然在這種開源框架中,也會用到萬能的設(shè)計模式。在Spring 中大概使用到了九種設(shè)計模式。這九種分別是簡單工廠(非二十三種設(shè)計模式中的一種)、工廠方法模式、單例模式、適配器模式、裝飾器模式、代理模式、觀察者模式、策略模式以及模塊方法模式。
簡單工廠模式又名靜態(tài)工廠方法,簡單工廠模式簡單來說就是由一個工廠類來接收參數(shù)并動態(tài)的決定創(chuàng)建哪一個產(chǎn)品類。
在Spring 中,Bean Factory 就是簡單工廠模式的應(yīng)用。它作為IOC 最基本的容器,負(fù)責(zé)生產(chǎn)和管理Bean,并且它還為其他具體的IOC 容器提供了基本規(guī)范。如果說它是Spring 里面最低層的接口,提供了最簡單的容器功能,那么Application Context 就是更高級的容器,它繼承Bean Factory 接口,還增加了更多新功能,如國際化,可訪問資源以及消息發(fā)送、響應(yīng)機(jī)制等。
第一步是創(chuàng)建一個Student 實體類。第二步是在配置文件中傳入?yún)?shù),通過id 屬性指定參數(shù),通過class 指定具體的類,通過scope 屬性來定義是否為單例。第三步是測試,創(chuàng)建一個main 函數(shù),通過new Class Path Xml Application Context 來指定xml 文件,用get Bean 方法來傳入?yún)?shù),從而獲取到xml 中配置的類。
在使用簡單工廠的時候通常不用創(chuàng)建簡單工廠類的實例,因此可以把簡單工廠類實現(xiàn)成一個工具類,直接使用靜態(tài)方法結(jié)果。也就是說簡單工廠的方法通常都是靜態(tài)的,所以也被稱為靜態(tài)工廠。如果放置客戶端隨意創(chuàng)造簡單工廠實例,也可以把簡單工廠的構(gòu)造方法私有化。想要理解Spring 里面的簡單工廠模式其實很簡單,想想我們在學(xué)習(xí)java 設(shè)計模式的時候,做簡單工廠實例的流程,其必不可缺的流程就是工廠類,沒有工廠你就什么也拿不到。在Spring 中,Bean Factory 就是這么一個工廠,如果沒有這個工廠,就好比我們需要工廠里生產(chǎn)的商品,但是拿到手還得我們自己動手,不僅麻煩還不利于日后的維護(hù)。
這種模式涉及到的是一個單一的類。該類只負(fù)責(zé)創(chuàng)建自己的對象,同時確保只創(chuàng)建單個對象。在上述簡單工廠模式實例中其實已經(jīng)設(shè)計到了單例模式的運(yùn)用。
在Spring 中,依賴注入默認(rèn)就是為單例,依賴注入是發(fā)生在Abstract Bean Factory 的get Bean 方法中,其中的do Get Bean方法調(diào)用get Singleton 進(jìn)行Bean 的創(chuàng)建。單例模式的定義為:保證一個類有且僅有一個實例,并提供一個訪問它的全局訪問點。Spring 對單例的實現(xiàn)就是完成了后面半句話,即提供了一個全局的訪問點Bean Factory。而且在Spring 中實現(xiàn)單例模式只需要設(shè)置一個屬性或者一個注解。
Xml 配置:在上面簡單工廠模式中有提到xml 文件配置,在配置中有這么一個屬性scope,將代碼中的Prototype 改成Singleton 即可。
注解:@Scope
在我們的項目中,有一些對象確實只需要創(chuàng)建一個就夠了,比如線程池、緩存、日志。創(chuàng)建的太多反而會成為負(fù)擔(dān),所以在Spring 中默認(rèn)的就是單例。一般我們都說,最成功的單例并不是雙重檢驗鎖,而是枚舉,枚舉本身就是一種單例,并且無法做到反射攻擊,再一個最優(yōu)雅的無非就是Spring 本身實現(xiàn)的單例:在Spring 中,在一些注解作用下的類默認(rèn)都是單例的,目前通過我對Spring 的了解,我認(rèn)為最優(yōu)注解為@Component,主要使用場景有:數(shù)據(jù)庫的配置、Redis 的配置、權(quán)限的配置、Filter 的過濾、攔截器、swagger 及自定義的時間轉(zhuǎn)換器、類型轉(zhuǎn)換器、對接第三方硬件時,調(diào)用硬件的dll、so文件等。我個人比較常遇到的就是數(shù)據(jù)庫配置以及攔截器的配置。當(dāng)然在Spring 中也不是所有注解在默認(rèn)情況下都是單例的,因為@Component+@Bean 并不是單例,在調(diào)用過程中可能會創(chuàng)建多個實例,出現(xiàn)錯誤,所以要避免這種組合使用,另外,在控制器層中的常用注解@Restcontroller 也是多例的。
代理模式是給某一個對象提供一個代理對象,并由代理對象來控制對原對象的引用.代理模式還分靜態(tài)代理與動態(tài)代理。
AOP(面向切面編程)五大通知類型:
圖1 五大通知類型
代碼為切面類,注解使用@Aspect,將該類定義標(biāo)識為一個切面供容器來讀取,用Logger Factory 來記錄日志,@Pointcut注解是植入Advice 的觸發(fā)條件,它定義的是表達(dá)式和方法簽名。方法簽名一定要是公開以及無返回值類型的,然后根據(jù)實際需求選擇圖3 中的五大通知類型。
結(jié)果:以登錄操作為例
圖2 日志
代理模式可以將那些與業(yè)務(wù)無關(guān),但又可以將一些業(yè)務(wù)模塊共同調(diào)用的責(zé)任或邏輯封裝起來。為了增加其代碼的復(fù)用性,降低各個模塊間的耦合度,并且有利于項目未來的可拓展性和可維護(hù)性。最常見的一些實用場景如下面這些:日志的記錄、跟蹤、優(yōu)化與監(jiān)控和事務(wù)的處理、持久化、性能優(yōu)化、資源池、連接池的管理、系統(tǒng)的權(quán)限管理以及緩存、錯誤處理、調(diào)試、加載等。上文便是通過AOP 實現(xiàn)了日志記錄。而且在Spring AOP 中實現(xiàn)的是一種動態(tài)代理,如果目標(biāo)方法有接口的時候會自動選用JDK 動態(tài)代理目標(biāo),相反如果方法沒有接口時候則會選擇選擇 CGLib 動態(tài)代理。
適配器模式的目的是將一個類接口轉(zhuǎn)變?yōu)榭蛻舳四繕?biāo)接口,從而使因不匹配而無法工作的兩個類能一起工作,因此又被稱為轉(zhuǎn)換器模式等。
前文提到,Spring AOP 是基于代理模式來實現(xiàn)的,在Spring AOP 中通過使用的 Advice(通知)來增強(qiáng)被代理類的功能。與之相關(guān)的接口為Advisor Adapter,通知的類型與圖1 中相似,分為方法前、方法后等等。每個類型的通知都有對應(yīng)的攔截器,Spring 需要將每個通知都封裝成對應(yīng)的攔截器類型,返回給容器,所以需要使用適配器模式對 Advice 進(jìn)行轉(zhuǎn)換。
Spring 框架的子模塊Spring MVC,使用處理器分離模型、控制和視圖的開發(fā)模式,提高系統(tǒng)服用性、可維護(hù)性和靈活性的開發(fā)模式,達(dá)到不同技術(shù)層級間松耦合的效果。其中,Dispatcher Servlet 根據(jù)請求信息調(diào)用Handler Mapping,解析請求對應(yīng)的Handler。解析到后,開始由Handler Adapter 適配器處理。它作為期望接口,具體的適配器實現(xiàn)類用于對目標(biāo)類進(jìn)行適配,控制器作為需要適配的類。
Spring AOP 在前文代理模式中已經(jīng)提到,這里就說說Spring MVC。Spring MVC 之所以要采用適配器模式,是因為當(dāng)在一個項目中,控制器種類繁多,每一個控制器都會有不同的請求來進(jìn)行處理,如果不使用適配器模式,就需要自行if else語句去判斷。如果這樣的話,每加一個控制器都需要加一個判斷語句,不僅使得系統(tǒng)難以維護(hù),還違反了設(shè)計模式中的開閉原則。
設(shè)計模式本身是作為一套眾人知曉,經(jīng)過分類編目,且被人們反復(fù)使用的代碼編寫經(jīng)驗的總結(jié)。但是,這套總結(jié)僅僅存在于代碼之上。我們在項目開發(fā),軟件開發(fā)中遇到的一些問題,僅憑著使用設(shè)計模式還是遠(yuǎn)遠(yuǎn)不夠的,于是Spring 應(yīng)運(yùn)而生。它是由于開發(fā)的復(fù)雜性而創(chuàng)建的。Spring 與現(xiàn)有的技術(shù)不同,它更多強(qiáng)調(diào)的是面向?qū)ο?。它的初衷便是為了讓軟件開發(fā)變得更加簡單,開發(fā)人員從以前的使用類轉(zhuǎn)向更好的使用接口,并且,它將使用接口的復(fù)雜度降到了最低,幾乎接近零。其實我們作為一個程序員,無論是前端還是后端,設(shè)計模式的重要性是其他所有框架所不能比擬的?,F(xiàn)在大多數(shù)框架中都用到了很多的設(shè)計模式。正是因為運(yùn)用到的這些設(shè)計模式,才使得我們在使用框架進(jìn)行項目開發(fā)時能夠做到游刃有余。