一、設計模式簡介
1.1 設計模式分為三大類:
(1)創(chuàng)建型模式驮履,共五種:工廠方法模式鱼辙、抽象工廠模式、單例模式玫镐、建造者模式座每、原型模式。
(2)結構型模式摘悴,共七種:適配器模式峭梳、裝飾器模式、代理模式、外觀模式葱椭、橋接模式捂寿、組合模式、享元模式孵运。
(3)行為型模式秦陋,共十一種:策略模式、模板方法模式治笨、觀察者模式驳概、迭代子模式、責任鏈模式旷赖、命令模式顺又、備忘錄模式、狀態(tài)模式等孵、訪問者模式稚照、中介者模式、解釋器模式俯萌。
1.2 設計模式總概況
1.3 設計模式的六大原則
(1)開閉原則(Open Close Principle)
開閉原則就是說對擴展開放果录,對修改關閉。在程序需要進行拓展的時候咐熙,不能去修改原有的代碼弱恒,實現(xiàn)一個熱插拔的效果。所以一句話概括就是:為了使程序的擴展性好棋恼,易于維護和升級斤彼。想要達到這樣的效果,我們需要使用接口和抽象類蘸泻,后面的具體設計中我們會提到這點琉苇。
(2)里氏代換原則(Liskov Substitution Principle)
里氏代換原則(Liskov Substitution Principle LSP)面向對象設計的基本原則之一。里氏代換原則中說悦施,任何基類可以出現(xiàn)的地方并扇,子類一定可以出現(xiàn)。LSP是繼承復用的基石抡诞,只有當衍生類可以替換掉基類穷蛹,軟件單位的功能不受到影響時,基類才能真正被復用昼汗,而衍生類也能夠在基類的基礎上增加新的行為肴熏。里氏代換原則是對“開-閉”原則的補充。實現(xiàn)“開-閉”原則的關鍵步驟就是抽象化顷窒。而基類與子類的繼承關系就是抽象化的具體實現(xiàn)蛙吏,所以里氏代換原則是對實現(xiàn)抽象化的具體步驟的規(guī)范源哩。—— From Baidu 百科
(3)依賴倒轉原則(Dependence Inversion Principle)
這個是開閉原則的基礎鸦做,具體內(nèi)容:真對接口編程励烦,依賴于抽象而不依賴于具體。
(4)接口隔離原則(Interface Segregation Principle)
這個原則的意思是:使用多個隔離的接口泼诱,比使用單個接口要好坛掠。還是一個降低類之間的耦合度的意思,從這兒我們看出治筒,其實設計模式就是一個軟件的設計思想屉栓,從大型軟件架構出發(fā),為了升級和維護方便耸袜。所以上文中多次出現(xiàn):降低依賴友多,降低耦合。
(5)迪米特法則(最少知道原則)(Demeter Principle)
為什么叫最少知道原則句灌,就是說:一個實體應當盡量少的與其他實體之間發(fā)生相互作用夷陋,使得系統(tǒng)功能模塊相對獨立欠拾。
(6)合成復用原則(Composite Reuse Principle)
原則是盡量使用合成/聚合的方式胰锌,而不是使用繼承。
二藐窄、設計模式詳解
2.1 工廠方法模式(Factory Method)
工廠方法模式分為三種:普通工廠模式资昧、多個工廠方法模式和靜態(tài)工廠方法模式。
2.1.1 普通工廠模式
普通工廠模式就是建立一個工廠類荆忍,對實現(xiàn)了同一接口的一些類進行實例的創(chuàng)建格带。
再回頭來理解這句話:普通工廠模式就是建立一個工廠類,對實現(xiàn)了同一接口的一些類進行實例的創(chuàng)建刹枉。
2.1.2 多個工廠方法模式
多個工廠方法模式叽唱,是對普通工廠方法模式的改進,多個工廠方法模式就是提供多個工廠方法微宝,分別創(chuàng)建對象棺亭。
再回頭來理解這句話:多個工廠方法模式,是對普通工廠方法模式的改進蟋软,多個工廠方法模式就是提供多個工廠方法镶摘,分別創(chuàng)建對象。
2.1.3 靜態(tài)工廠方法模式
靜態(tài)工廠方法模式岳守,將上面的多個工廠方法模式里的方法置為靜態(tài)的凄敢,不需要創(chuàng)建實例,直接調(diào)用即可湿痢。
再回顧:靜態(tài)工廠方法模式涝缝,將上面的多個工廠方法模式里的方法置為靜態(tài)的,不需要創(chuàng)建實例,直接調(diào)用即可俊卤。
2.2 抽象工廠模式(Abstract Factory)
工廠方法模式有一個問題就是嫩挤,類的創(chuàng)建依賴工廠類,也就是說消恍,如果想要拓展程序岂昭,必須對工廠類進行修改,這違背了閉包原則狠怨。
為解決這個問題约啊,我們來看看抽象工廠模式:創(chuàng)建多個工廠類,這樣一旦需要增加新的功能佣赖,直接增加新的工廠類就可以了恰矩,不需要修改之前的代碼。
再回顧:抽象工廠模式就是創(chuàng)建多個工廠類憎蛤,這樣一旦需要增加新的功能外傅,直接增加新的工廠類就可以了,不需要修改之前的代碼俩檬。
2.3 單例模式(Singleton)
2.4 建造者模式(Builder)
建造者模式:是將一個復雜的對象的構建與它的表示分離萎胰,使得同樣的構建過程可以創(chuàng)建不同的表示。
回顧:建造者模式:是將一個復雜的對象的構建與它的表示分離棚辽,使得同樣的構建過程可以創(chuàng)建不同的表示技竟。
2.5 原型模式(Prototype)
該模式的思想就是將一個對象作為原型,對其進行復制屈藐、克隆榔组,產(chǎn)生一個和原對象類似的新對象。
說道復制對象联逻,我將結合對象的淺復制和深復制來說一下搓扯,首先需要了解對象深、淺復制的概念
2.6 適配器模式(Adapter)
定義:適配器模式將某個類的接口轉換成客戶端期望的另一個接口表示包归,主的目的是兼容性锨推,讓原本因接口不匹配不能一起工作的兩個類可以協(xié)同工作。其別名為包裝器(Wrapper)箫踩。
適配器模式主要分為三類:類的適配器模式爱态、對象的適配器模式、接口的適配器模式
2.7 裝飾模式(Decorator)
裝飾模式:在不必改變原類文件和使用繼承的情況下境钟,動態(tài)地擴展一個對象的功能锦担。它是通過創(chuàng)建一個包裝對象,也就是裝飾來包裹真實的對象慨削。
裝飾模式的特點:
(1)裝飾對象和真實對象有相同的接口洞渔。這樣客戶端對象就能以和真實對象相同的方式和裝飾對象交互套媚。(2)裝飾對象包含一個真實對象的引用(reference)(3)裝飾對象接受所有來自客戶端的請求。它把這些請求轉發(fā)給真實的對象磁椒。(4)裝飾對象可以在轉發(fā)這些請求以前或以后增加一些附加功能堤瘤。這樣就確保了在運行時,不用修改給定對象的結構就可以在外部增加附加的功能浆熔。在面向對象的設計中本辐,通常是通過繼承來實現(xiàn)對給定類的功能擴展。繼承不能做到這一點医增,繼承的功能是靜態(tài)的慎皱,不能動態(tài)增刪。
2.8 代理模式(Proxy)
代理模式就是多一個代理類出來叶骨,替原對象進行一些操作茫多。代理類就像中介,它比我們掌握著更多的信息忽刽。其目的就是為其他對象提供一個代理以控制對某個真實對象的訪問天揖。代理類負責為委托類預處理消息,過濾消息并轉發(fā)消息跪帝,以及進行消息被委托類執(zhí)行后的后續(xù)處理今膊。
(1)靜態(tài)代理
(2)動態(tài)代理
(3)Cglib代理
2.9 外觀模式(Facade)
外觀模式是為了解決類與類之間的依賴關系的,像spring一樣歉甚,可以將類和類之間的關系配置到配置文件中万细,而外觀模式就是將他們的關系放在一個Facade類中扑眉,降低了類類之間的耦合度纸泄,該模式中沒有涉及到接口。
2.10 橋接模式(Bridge)
在軟件系統(tǒng)中腰素,某些類型由于自身的邏輯聘裁,它具有兩個或多個維度的變化,那么如何應對這種“多維度的變化”弓千?如何利用面向對象的技術來使得該類型能夠輕松的沿著多個方向進行變化衡便,而又不引入額外的復雜度?這就要使用Bridge模式洋访。
2.11 組合模式(Composite)
組合模式镣陕,將對象組合成樹形結構以表示“部分-整體”的層次結構,組合模式使得用戶對單個對象和組合對象的使用具有一致性姻政。掌握組合模式的重點是要理解清楚 “部分/整體” 還有 ”單個對象“ 與 “組合對象” 的含義
2.12 享元模式(Flyweight)
享元模式的主要目的是實現(xiàn)對象的共享呆抑,即共享池,當系統(tǒng)中對象多的時候可以減少內(nèi)存的開銷汁展,通常與工廠模式一起使用鹊碍。
2.13 策略模式(strategy)
策略模式定義了一系列算法厌殉,并將每個算法封裝起來,使他們可以相互替換侈咕,且算法的變化不會影響到使用算法的客戶公罕。需要設計一個接口,為一系列實現(xiàn)類提供統(tǒng)一的方法耀销,多個實現(xiàn)類實現(xiàn)該接口楼眷,設計一個抽象類(可有可無,屬于輔助類)熊尉,提供輔助函數(shù)
2.14 模板方法模式(Template Method)
解釋一下模板方法模式摩桶,就是指:一個抽象類中,有一個主方法帽揪,再定義1...n個方法硝清,可以是抽象的,也可以是實際的方法转晰,定義一個類芦拿,繼承該抽象類,重寫抽象方法查邢,通過調(diào)用抽象類蔗崎,實現(xiàn)對子類的調(diào)用
2.15 觀察者模式(Observer)
包括這個模式在內(nèi)的接下來的四個模式,都是類和類之間的關系扰藕,不涉及到繼承缓苛,學的時候應該?記得歸納,記得本文最開始的那個圖邓深。觀察者模式很好理解未桥,類似于郵件訂閱和RSS訂閱,當我們?yōu)g覽一些博客或wiki時芥备,經(jīng)常會看到RSS圖標冬耿,就這的意思是,當你訂閱了該文章萌壳,如果后續(xù)有更新亦镶,會及時通知你。其實袱瓮,簡單來講就一句話:當一個對象變化時缤骨,其它依賴該對象的對象都會收到通知,并且隨著變化尺借!對象之間是一種一對多的關系
2.16 迭代子模式(Iterator)
顧名思義绊起,迭代器模式就是順序訪問聚集中的對象,一般來說褐望,集合中非常常見勒庄,如果對集合類比較熟悉的話串前,理解本模式會十分輕松。這句話包含兩層意思:一是需要遍歷的對象实蔽,即聚集對象荡碾,二是迭代器對象,用于對聚集對象進行遍歷訪問
2.17 責任鏈模式(Chain of Responsibility)
接下來我們將要談談責任鏈模式局装,有多個對象坛吁,每個對象持有對下一個對象的引用,這樣就會形成一條鏈铐尚,請求在這條鏈上傳遞拨脉,直到某一對象決定處理該請求。但是發(fā)出者并不清楚到底最終那個對象會處理該請求宣增,所以玫膀,責任鏈模式可以實現(xiàn),在隱瞞客戶端的情況下爹脾,對系統(tǒng)進行動態(tài)的調(diào)整帖旨。
2.18 命令模式(Command)
命令模式很好理解,舉個例子灵妨,司令員下令讓士兵去干件事情解阅,從整個事情的角度來考慮,司令員的作用是泌霍,發(fā)出口令货抄,口令經(jīng)過傳遞,傳到了士兵耳朵里朱转,士兵去執(zhí)行蟹地。這個過程好在,三者相互解耦肋拔,任何一方都不用去依賴其他人锈津,只需要做好自己的事兒就行呀酸,司令員要的是結果凉蜂,不會去關注到底士兵是怎么實現(xiàn)的。
2.19 備忘錄模式(Memento)
主要目的是保存一個對象的某個狀態(tài)性誉,以便在適當?shù)臅r候恢復對象窿吩,個人覺得叫備份模式更形象些,通俗的講下:假設有原始類A错览,A中有各種屬性纫雁,A可以決定需要備份的屬性,備忘錄類B是用來存儲A的一些內(nèi)部狀態(tài)倾哺,類C呢轧邪,就是一個用來存儲備忘錄的刽脖,且只能存儲,不能修改等操作忌愚。
2.20?狀態(tài)模式(State)
核心思想就是:當對象的狀態(tài)改變時曲管,同時改變其行為,很好理解硕糊!就拿QQ來說院水,有幾種狀態(tài),在線简十、隱身檬某、忙碌等,每個狀態(tài)對應不同的操作螟蝙,而且你的好友也能看到你的狀態(tài)恢恼,所以,狀態(tài)模式就兩點:1胰默、可以通過改變狀態(tài)來獲得不同的行為厅瞎。2、你的好友能同時看到你的變化初坠。
2.21 訪問者模式(Visitor)
訪問者模式把數(shù)據(jù)結構和作用于結構上的操作解耦合和簸,使得操作集合可相對自由地演化。訪問者模式適用于數(shù)據(jù)結構相對穩(wěn)定算法又易變化的系統(tǒng)碟刺。因為訪問者模式使得算法操作增加變得容易锁保。若系統(tǒng)數(shù)據(jù)結構對象易于變化,經(jīng)常有新的數(shù)據(jù)對象增加進來半沽,則不適合使用訪問者模式爽柒。訪問者模式的優(yōu)點是增加操作很容易,因為增加操作意味著增加新的訪問者者填。訪問者模式將有關行為集中到一個訪問者對象中浩村,其改變不影響系統(tǒng)數(shù)據(jù)結構。其缺點就是增加新的數(shù)據(jù)結構很困難占哟。
2.22 中介者模式(Mediator)
中介者模式也是用來降低類類之間的耦合的心墅,因為如果類類之間有依賴關系的話,不利于功能的拓展和維護榨乎,因為只要修改一個對象怎燥,其它關聯(lián)的對象都得進行修改。如果使用中介者模式蜜暑,只需關心和Mediator類的關系铐姚,具體類類之間的關系及調(diào)度交給Mediator就行,這有點像spring容器的作用肛捍。
2.23?解釋器模式(Interpreter
解釋器模式是我們暫時的最后一講隐绵,一般主要應用在OOP開發(fā)中的編譯器的開發(fā)中之众,所以適用面比較窄。
三依许、Spring的九種設計模式
3.1 簡單工廠(Factory Method)
又叫做靜態(tài)工廠方法(StaticFactory Method)模式酝枢,但不屬于23種GOF設計模式之一。?簡單工廠模式的實質是由一個工廠類根據(jù)傳入的參數(shù)悍手,動態(tài)決定應該創(chuàng)建哪一個產(chǎn)品類帘睦。?spring中的BeanFactory就是簡單工廠模式的體現(xiàn),根據(jù)傳入一個唯一的標識來獲得bean對象坦康,但是否是在傳入?yún)?shù)后創(chuàng)建還是傳入?yún)?shù)前創(chuàng)建這個要根據(jù)具體情況來定竣付。如下配置,就是在HelloItxxz 類中創(chuàng)建一個itxxzBean滞欠。
3.2 工廠方法(Factory Method)
通常由應用程序直接使用new創(chuàng)建新的對象古胆,為了將對象的創(chuàng)建和使用相分離,采用工廠模式,即應用程序將對象的創(chuàng)建及初始化職責交給工廠對象筛璧。
一般情況下,應用程序有自己的工廠對象來創(chuàng)建bean.如果將應用程序自己的工廠對象交給Spring管理,那么Spring管理的就不是普通的bean,而是工廠Bean逸绎。
3.3 單例模式(Singleton)
保證一個類僅有一個實例,并提供一個訪問它的全局訪問點夭谤。?spring中的單例模式完成了后半句話棺牧,即提供了全局的訪問點BeanFactory。但沒有從構造器級別去控制單例朗儒,這是因為spring管理的是是任意的java對象颊乘。?
3.4適配器(Adapter)
在Spring的Aop中,使用的Advice(通知)來增強被代理類的功能醉锄。Spring實現(xiàn)這一AOP功能的原理就使用代理模式(1乏悄、JDK動態(tài)代理。2恳不、CGLib字節(jié)碼生成技術代理檩小。)對類進行方法級別的切面增強,即烟勋,生成被代理類的代理類规求,并在代理類的方法前,設置攔截器神妹,通過執(zhí)行攔截器重的內(nèi)容增強了代理方法的功能颓哮,實現(xiàn)的面向切面編程。
3.5 包裝器(Decorator)
在我們的項目中遇到這樣一個問題:我們的項目需要連接多個數(shù)據(jù)庫鸵荠,而且不同的客戶在每次訪問中根據(jù)需要會去訪問不同的數(shù)據(jù)庫。我們以往在spring和hibernate框架中總是配置一個數(shù)據(jù)源伤极,因而sessionFactory的dataSource屬性總是指向這個數(shù)據(jù)源并且恒定不變蛹找,所有DAO在使用sessionFactory的時候都是通過這個數(shù)據(jù)源訪問數(shù)據(jù)庫姨伤。但是現(xiàn)在,由于項目的需要庸疾,我們的DAO在訪問sessionFactory的時候都不得不在多個數(shù)據(jù)源中不斷切換乍楚,問題就出現(xiàn)了:如何讓sessionFactory在執(zhí)行數(shù)據(jù)持久化的時候,根據(jù)客戶的需求能夠動態(tài)切換不同的數(shù)據(jù)源届慈?我們能不能在spring的框架下通過少量修改得到解決徒溪?是否有什么設計模式可以利用呢??首先想到在spring的applicationContext中配置所有的dataSource金顿。這些dataSource可能是各種不同類型的臊泌,比如不同的數(shù)據(jù)庫:Oracle、SQL Server揍拆、MySQL等渠概,也可能是不同的數(shù)據(jù)源:比如apache 提供的org.apache.commons.dbcp.BasicDataSource、spring提供的org.springframework.jndi.JndiObjectFactoryBean等嫂拴。然后sessionFactory根據(jù)客戶的每次請求播揪,將dataSource屬性設置成不同的數(shù)據(jù)源,以到達切換數(shù)據(jù)源的目的筒狠。 spring中用到的包裝器模式在類名上有兩種表現(xiàn):一種是類名中含有Wrapper猪狈,另一種是類名中含有Decorator”缒眨基本上都是動態(tài)地給一個對象添加一些額外的職責罪裹。?
3.6 代理(Proxy)
為其他對象提供一種代理以控制對這個對象的訪問。??從結構上來看和Decorator模式類似运挫,但Proxy是控制状共,更像是一種對功能的限制,而Decorator是增加職責谁帕。? spring的Proxy模式在aop中有體現(xiàn)峡继,比如JdkDynamicAopProxy和Cglib2AopProxy。?
3.7 觀察者(Observer)
定義對象間的一種一對多的依賴關系匈挖,當一個對象的狀態(tài)發(fā)生改變時碾牌,所有依賴于它的對象都得到通知并被自動更新。 spring中Observer模式常用的地方是listener的實現(xiàn)儡循。如ApplicationListener舶吗。
3.8 策略(Strategy)
定義一系列的算法,把它們一個個封裝起來择膝,并且使它們可相互替換誓琼。本模式使得算法可獨立于使用它的客戶而變化。?spring中在實例化對象的時候用到Strategy模式
3.9 模板方法(Template Method)
定義一個操作中的算法的骨架,而將一些步驟延遲到子類中腹侣。Template Method使得子類可以不改變一個算法的結構即可重定義該算法的某些特定步驟叔收。 Template Method模式一般是需要繼承的。這里想要探討另一種對Template Method的理解傲隶。spring中的JdbcTemplate饺律,在用這個類時并不想去繼承這個類,因為這個類的方法太多跺株,但是我們還是想用到JdbcTemplate已有的穩(wěn)定的复濒、公用的數(shù)據(jù)庫連接,那么我們怎么辦呢乒省?我們可以把變化的東西抽出來作為一個參數(shù)傳入JdbcTemplate的方法中巧颈。但是變化的東西是一段代碼,而且這段代碼會用到JdbcTemplate中的變量作儿。怎么辦洛二?那我們就用回調(diào)對象吧。在這個回調(diào)對象中定義一個操縱JdbcTemplate中變量的方法攻锰,我們?nèi)崿F(xiàn)這個方法晾嘶,就把變化的東西集中到這里了。然后我們再傳入這個回調(diào)對象到JdbcTemplate娶吞,從而完成了調(diào)用垒迂。這可能是Template Method不需要繼承的另一種實現(xiàn)方式吧。?
JdbcTemplate執(zhí)行execute方法:
?
四妒蛇、Mybatis用到的設計模式
(1)Builder模式机断,例如SqlSessionFactoryBuilder、XMLConfigBuilder绣夺、XMLMapperBuilder吏奸、XMLStatementBuilder、CacheBuilder陶耍;
(2)工廠模式奋蔚,例如SqlSessionFactory、ObjectFactory烈钞、MapperProxyFactory泊碑;
(3)單例模式,例如ErrorContext和LogFactory毯欣;
(4)代理模式馒过,Mybatis實現(xiàn)的核心,比如MapperProxy酗钞、ConnectionLogger腹忽,用的jdk的動態(tài)代理来累;還有executor.loader包使用了cglib或者javassist達到延遲加載的效果;
(5)組合模式留凭,例如SqlNode和各個子類ChooseSqlNode等佃扼;
(6)模板方法模式偎巢,例如BaseExecutor和SimpleExecutor蔼夜,還有BaseTypeHandler和所有的子類例如IntegerTypeHandler;
(7)適配器模式压昼,例如Log的Mybatis接口和它對jdbc求冷、log4j等各種日志框架的適配實現(xiàn);
(8)裝飾者模式窍霞,例如Cache包中的cache.decorators子包中等各個裝飾者的實現(xiàn)匠题;
(9)迭代器模式,例如迭代器模式PropertyTokenizer但金;
五韭山、設計模式參考文獻
http://www.importnew.com/18390.html
http://blog.csdn.net/zhangerqing/article/details/8239539
http://www.cnblogs.com/zuoxiaolong/p/pattern26.html
http://c.biancheng.net/design_pattern/