1.spring 中常用的設計模式有23中
分類 | 設計模式 |
創建型 | 工廠方法模式(FactoryMethod)、抽象工廠模式(AbstractFactory)、 |
結構型 | 適配器模式(Adapter)、橋接模式(Bridge)、組合模式(Composite)、 裝飾器模式(Decorator)、門面模式(Facade)、享元模式(Flyweight)、代理模式(Proxy) |
行為型 | 解釋器模式(Interpreter)、模板方法模式(TemplateMethod)、 |
通常來說,設計模式都是混合使用,不會獨立應用。利用窮舉法充分理解設計模式的應用場景。在平時的應用中,不是用設計模式去生搬硬套,而是根據具體業務問題需要時借鑒。
2、設計模式在應用中遵循六大原則:
a、開閉原則(OpenClosePrinciple)
開閉原則就是說對擴展開放,對修改關閉。在程序需要進行拓展的時候,不能去修改原有的代碼,實現
一個熱插拔的效果。所以一句話概括就是:為了使程序的擴展性好,易於維護和升級。想要達到這樣的
效果,我們需要使用接口和抽象類,后面的具體設計中我們會提到這點。
b、里氏代換原則(LiskovSubstitutionPrinciple)
里氏代換原則(LiskovSubstitutionPrincipleLSP)
面向對象設計的基本原則之一。里氏代換原則中說,任何基類可以出現的地方,子類一定可以出現。LSP是繼承復用的基石,只有當衍生類可以替換掉基類,軟件單位的功能不受到影響時,基類才能真正被復用,而衍生類也能夠在基類的基礎上增加新的行為。里氏代換原則是對“開-閉”原則的補充。實現“開-閉”原則的關鍵步驟就是抽象化。而基類與子類的繼承關系就是抽象化的具體實現,所以里氏代換原則是對實現抽象化的具體步驟的規范。
c、依賴倒轉原則(DependenceInversionPrinciple)
這個是開閉原則的基礎,具體內容:針對接口編程,依賴於抽象而不依賴於具體。
d、接口隔離原則(InterfaceSegregationPrinciple)
這個原則的意思是:使用多個隔離的接口,比使用單個接口要好。還是一個降低類之間的耦合度的意思,從這兒我們看出,其實設計模式就是一個軟件的設計思想,從大型軟件架構出發,為了升級和維護方便。所以上文中多次出現:降低依賴,降低耦合。
e、迪米特法則(最少知道原則)(DemeterPrinciple)
為什么叫最少知道原則,就是說:一個實體應當盡量少的與其他實體之間發生相互作用,使得系統功能模塊相對獨立。
f、合成復用原則(CompositeReusePrinciple)
原則是盡量使用合成/聚合的方式,而不是使用繼承。
設計模式之間的關系圖
1.1、簡單工廠模式(Factory)
應用場景:又叫做靜態工廠方法(StaticFactoryMethod)模式,但不屬於23種設計模式之一。簡單工廠模式的實質是由一個工廠類根據傳入的參數,動態決定應該創建哪一個產品類。
Spring中的BeanFactory就是簡單工廠模式的體現,根據傳入一個唯一的標識來獲得Bean對象,但是否是在傳入參數后創建還是傳入參數前創建這個要根據具體情況來定。
歸類 | 特點 | 窮舉 |
創建型模式 |
是復雜工廠模式的思維模型 | 批量生產、標准化 |
1.2、工廠方法模式(FactoryMethod)
應用場景:通常由應用程序直接使用new創建新的對象,為了將對象的創建和使用相分離,采用工廠模式,即應用程序將對象的創建及初始化職責交給工廠對象。
一般情況下,應用程序有自己的工廠對象來創建Bean.如果將應用程序自己的工廠對象交給Spring管理,那么Spring
管理的就不是普通的Bean,而是工廠Bean。
歸類 | 特點 | 窮舉 |
創建型模式 |
對於調用者來說,隱藏了復雜的邏輯處理過程,調用者只關心執行結果。 對於工廠來說要對結果負責,保證生產出符合規范的產品。 |
流水線生產 |
1.3、單例模式(Singleton)
應用場景:保證一個類僅有一個實例,並提供一個訪問它的全局訪問點。
Spring中的單例模式完成了后半句話,即提供了全局的訪問點BeanFactory。但沒有從構造器級別去控制單例,這是因為Spring管理的是是任意的Java對象。Spring下默認的Bean均為單例。
歸類 | 特點 | 窮舉 |
創建型模式 | 保證從系統啟動到系統終止,全過程只會產生一個實例。 當我們在應用中遇到功能性沖突的時候,需要使用單例模式。 |
配置文件、日歷、OC容器 |
常用單例模式寫法:餓漢式、懶漢式、注冊式、序列化。
1.4、原型模式(Prototype)
應用場景:原型模式就是從一個對象再創建另外一個可定制的對象,而且不需要知道任何創建的細節。
所謂原型模式,就是Java中的克隆技術,以某個對象為原型。復制出新的對象。顯然新的對象具備原型對象的特點,效率高(避免了重新執行構造過程步驟)。
歸類 | 特點 | 窮舉 |
創建型模式 | 首先有一個原型。 數據內容相同,但對象實例不同(完全兩個個體)。 |
孫悟空吹毫毛 |
1.5、代理模式(Proxy)
應用場景:為其他對象提供一種代理以控制對這個對象的訪問。從結構上來看和Decorator模式類似,但Proxy是控制,更像是一種對功能的限制,而Decorator是增加職責。
Spring的Proxy模式在AOP中有體現,比如JdkDynamicAopProxy和Cglib2AopProxy。
歸類 | 特點 | 窮舉 |
結構型模式 | 執行者、被代理人對於被代理人來說,這件事情是一定要做的, 但是我自己又不想做或者沒有時間做。對於代理人而言, 需要獲取到被代理的人個人資料,只是參與整個過程的某個或幾個環節。 |
租房中介、售票黃牛、婚介、經紀人、 快遞、事務代理、非侵入式日志監聽 |
1.6、策略模式(Strategy)
應用場景:定義一系列的算法,把它們一個個封裝起來,並且使它們可相互替換。本模式使得算法可獨
立於使用它的客戶而變化。
Spring中在實例化對象的時候用到Strategy模式,在SimpleInstantiationStrategy有使用。
歸類 | 特點 | 窮舉 |
行為型模式 | 最終執行結果是固定的。執行過程和執行邏輯不一樣 | 旅游出行方式 |
1.7、模板方法模式(TemplateMethod)
定義一個操作中的算法的骨架,而將一些步驟延遲到子類中。TemplateMethod使得子類可以不改變一個算法的結構即可重定義該算法的某些特定步驟。
TemplateMethod模式一般是需要繼承的。這里想要探討另一種對TemplateMethod的理解。Spring中的JdbcTemplate,在用這個類時並不想去繼承這個類,因為這個類的方法太多,但是我們還是想用到JdbcTemplate
已有的穩定的、公用的數據庫連接,那么我們怎么辦呢?我們可以把變化的東西抽出來作為一個參數傳入JdbcTemplate的方法中。但是變化的東西是一段代碼,而且這段代碼會用到JdbcTemplate中的變量。怎么辦?那我們就用回調對象吧。在這個回調對象中定義一個操縱JdbcTemplate中變量的方法,我們去實現這個方法,就把變化的東西集中到這里了。然后我們再傳入這個回調對象到JdbcTemplate,從而完成了調用。這就是TemplateMethod不需要繼承的另一種實現方式。
歸類 | 特點 | 窮舉 |
行為型模式 | 執行流程固定,但中間有些步驟有細微差別(運行時才確定)。 可實現批量生產。 |
SpringORM數據模型 |
1.8、委派模式(Delegate)
應用場景:不屬於23種設計模式之一,是面向對象設計模式中常用的一種模式。這種模式的原理為類B和類A是兩個互相沒有任何關系的類,B具有和A一模一樣的方法和屬性;並且調用B中的方法,屬性就是調用A中同名的方法和屬性。B好像就是一個受A授權委托的中介。第三方的代碼不需要知道A的存在,也不需要和A發生直接的聯系,通過B就可以直接使用A的功能,這樣既能夠使用到A的各種功能,又能夠很好的將A保護起來了,一舉兩得。
歸類 | 特點 | 窮舉 |
行為型模式 | 要和代理模式區分開來。 持有被委托人的引用。 不關心過程,只關心結果。 |
經理派發工作任務、Dispatcher |
1.9、適配器模式(Adapter)
SpringAOP模塊對BeforeAdvice、AfterAdvice、ThrowsAdvice三種通知類型的支持實際上是借助適配器模式來實現的,這樣的好處是使得框架允許用戶向框架中加入自己想要支持的任何一種通知類型,上述三種通知類型是SpringAOP模塊定義的,它們是AOP聯盟定義的Advice的子類型。
歸類 | 特點 | 窮舉 |
結構型模式 | 注重兼容、轉換。 適配者與被適配這之間沒有層級關系,也沒有必然聯系。 滿足has-a的關系。 |
編碼解碼、一拖三充電頭、HDMI轉VGA、Type-C轉USB |
1.10、裝飾器模式(Decorator)
應用場景:在我們的項目中遇到這樣一個問題:我們的項目需要連接多個數據庫,而且不同的客戶在每
次訪問中根據需要會去訪問不同的數據庫。我們以往在Spring和Hibernate框架中總是配置一個數據源,因而SessionFactory的DataSource屬性總是指向這個數據源並且恆定不變,所有DAO在使用SessionFactory的時候都是通過這個數據源訪問數據庫。但是現在,由於項目的需要,我們的DAO在訪問SessionFactory的時候都不得不在多個數據源中不斷切換,問題就出現了:如何讓SessionFactory在執行數據持久化的時候,根據客戶的需求能夠動態切換不同的數據源?我們能不能在Spring的框架下通過少量修改得到解決?是否有什么設計模式可以利用呢?
首先想到在Spring的ApplicationContext中配置所有的DataSource。這些DataSource可能是各種不同類型的,比如不同的數據庫:Oracle、SQLServer、MySQL等,也可能是不同的數據源:比如Apache提供的org.apache.commons.dbcp.BasicDataSource、Spring提供的org.springframework.jndi.JndiObjectFactoryBean等。然后SessionFactory根據客戶的每次請求,將DataSource屬性設置成不同的數據源,以到達切換數據源的目的。
Spring中用到的包裝器模式在類名上有兩種表現:一種是類名中含有Wrapper,另一種是類名中含有Decorator。基本上都是動態地給一個對象添加一些額外的職責。
歸類 | 特點 | 窮舉 |
結構型模式 | 1、注重覆蓋、擴展。 2、裝飾器和被裝飾器都實現同一個接口, 主要目的是為了擴展之后依舊保留OOP關系(同宗同源)。 3、滿足is-a的關系。 |
IO流包裝、數據源包裝、簡歷包裝 |
1.11、觀察者模式(Observer)
應用場景:定義對象間的一種一對多的依賴關系,當一個對象的狀態發生改變時,所有依賴於它的對象
都得到通知並被自動更新。
Spring中Observer模式常用的地方是Listener的實現。如ApplicationListener。
歸類 | 特點 | 窮舉 |
行為型模式 | 一般由兩個角色組成:發布者和訂閱者(觀察者)。 觀察者通常有一個回調,也可以沒有。 |
監聽器、日志收集、短信通知、郵件通知 |
1.12、各設計模式對比及編程思想總結
設計模式 | 一句話歸納 |
工廠模式(Factory) | 只對結果負責,不要三無產品。 |
單例模式(Singleton) | 保證獨一無二。 |
適配器模式(Adapter) | 需要一個轉換頭(兼容)。 |
裝飾器模式(Decorator) | 需要包裝,但不改變本質(同宗同源)。 |
代理模式(Proxy) | 辦事要求人,所以找代理。 |
觀察者模式(Observer) | 完成時通知我。 |
策略模式(Strategy) | 我行我素,達到目的就行。 |
模板模式(Template) | 流程標准化,原料自己加。 |
委派模式(Delegate) | 干活是你的(普通員工),功勞是我的(項目經理)。 |
原型模式(Prototype) | 拔一根猴毛,吹出千萬個。 |
編程思想總結
Spring思想 | 應用場景(特點) | 一句話歸納 |
AOP | AspectOrientedProgramming(面向切面編程) 找出多個類中有一定規律的代碼,開發時拆開,運行時再合並。 面向切面編程,即面向規則編程。 |
解耦,專人做專事。 |
OOP | ObjectOrientedProgramming(面向對象編程) 歸納總結生活中一切事物。 |
封裝、繼承、多態。 |
BOP | BeanOrientedProgramming(面向Bean編程) 面向Bean(普通的java類)設計程序。 |
一切從Bean開始。 |
IOC | InversionofControl(控制反轉) 將new對象的動作交給Spring管理,並由Spring保存已創建的對象(IOC容器)。 |
轉交控制權(即控制權反轉)。 |
DI/DL | DependencyInjection(依賴注入)或者DependencyLookup(依賴查找) 依賴注入、依賴查找,Spring不僅保存自己創建的對象,而且保存對象與對象之間的關系。 注入即賦值,主要三種方式構造方法、set方法、直接賦值。 |
先理清關系再賦值。 |