幾種設(shè)計(jì)模式總結(jié)
1.單例模式:
實(shí)現(xiàn)方式:
a.將被實(shí)現(xiàn)的類(lèi)的構(gòu)造方法設(shè)計(jì)成private的。
b.添加此類(lèi)引用的靜態(tài)成員變量,并為其實(shí)例化。
c.在被實(shí)現(xiàn)的類(lèi)中提供公共的CreateInstance函數(shù),返回實(shí)例化的此類(lèi),就是b中的靜態(tài)成員變量。
應(yīng)用場(chǎng)景:
優(yōu)點(diǎn):
1.在單例模式中,活動(dòng)的單例只有一個(gè)實(shí)例,對(duì)單例類(lèi)的所有實(shí)例化得到的都是相同的一個(gè)實(shí)例。這樣就防止其它對(duì)象對(duì)自己的實(shí)例化,確保所有的對(duì)象都訪(fǎng)問(wèn)一個(gè)實(shí)例
2.單例模式具有一定的伸縮性,類(lèi)自己來(lái)控制實(shí)例化進(jìn)程,類(lèi)就在改變實(shí)例化進(jìn)程上有相應(yīng)的伸縮性。
3.提供了對(duì)唯一實(shí)例的受控訪(fǎng)問(wèn)。
4.由于在系統(tǒng)內(nèi)存中只存在一個(gè)對(duì)象,因此可以節(jié)約系統(tǒng)資源,當(dāng)需要頻繁創(chuàng)建和銷(xiāo)毀的對(duì)象時(shí)單例模式無(wú)疑可以提高系統(tǒng)的性能。
5.允許可變數(shù)目的實(shí)例。
6.避免對(duì)共享資源的多重占用。
缺點(diǎn):
1.不適用于變化的對(duì)象,如果同一類(lèi)型的對(duì)象總是要在不同的用例場(chǎng)景發(fā)生變化,單例就會(huì)引起數(shù)據(jù)的錯(cuò)誤,不能保存彼此的狀態(tài)。
2.由于單利模式中沒(méi)有抽象層,因此單例類(lèi)的擴(kuò)展有很大的困難。
3.單例類(lèi)的職責(zé)過(guò)重,在一定程度上違背了“單一職責(zé)原則”。
4.濫用單例將帶來(lái)一些負(fù)面問(wèn)題,如為了節(jié)省資源將數(shù)據(jù)庫(kù)連接池對(duì)象設(shè)計(jì)為的單例類(lèi),可能會(huì)導(dǎo)致共享連接池對(duì)象的程序過(guò)多而出現(xiàn)連接池溢出;如果實(shí)例化的對(duì)象長(zhǎng)時(shí)間不被利用,系統(tǒng)會(huì)認(rèn)為是垃圾而被回收,這將導(dǎo)致對(duì)象狀態(tài)的丟失。
使用注意事項(xiàng):
1.使用時(shí)不能用反射模式創(chuàng)建單例,否則會(huì)實(shí)例化一個(gè)新的對(duì)象
2.使用懶單例模式時(shí)注意線(xiàn)程安全問(wèn)題
3.單例模式和懶單例模式構(gòu)造方法都是私有的,因而是不能被繼承的,有些單例模式可以被繼承(如登記式模式.
適用場(chǎng)景:
單例模式只允許創(chuàng)建一個(gè)對(duì)象,因此節(jié)省內(nèi)存,加快對(duì)象訪(fǎng)問(wèn)速度,因此對(duì)象需要被公用的場(chǎng)合適合使用,如多個(gè)模塊使用同一個(gè)數(shù)據(jù)源連接對(duì)象等等。如:
1.需要頻繁實(shí)例化然后銷(xiāo)毀的對(duì)象。
2.創(chuàng)建對(duì)象時(shí)耗時(shí)過(guò)多或者耗資源過(guò)多,但又經(jīng)常用到的對(duì)象。
3.有狀態(tài)的工具類(lèi)對(duì)象。
4.頻繁訪(fǎng)問(wèn)數(shù)據(jù)庫(kù)或文件的對(duì)象。
以下都是單例模式的經(jīng)典使用場(chǎng)景:
1.資源共享的情況下,避免由于資源操作時(shí)導(dǎo)致的性能或損耗等。如上述中的日志文件,應(yīng)用配置。
2.控制資源的情況下,方便資源之間的互相通信。如線(xiàn)程池等。
應(yīng)用場(chǎng)景舉例:
1.外部資源:每臺(tái)計(jì)算機(jī)有若干個(gè)打印機(jī),但只能有一個(gè)PrinterSpooler,以避免兩個(gè)打印作業(yè)同時(shí)輸出到打印機(jī)。內(nèi)部資源:大多數(shù)軟件都有一個(gè)(或多個(gè))屬性文件存放系統(tǒng)配置,這樣的系統(tǒng)應(yīng)該有一個(gè)對(duì)象管理這些屬性文件
2.Windows的TaskManager(任務(wù)管理器)就是很典型的單例模式(這個(gè)很熟悉吧),想想看,是不是呢,你能打開(kāi)兩個(gè)windowstaskmanager嗎?不信你自己試試看哦~
3.windows的RecycleBin(回收站)也是典型的單例應(yīng)用。在整個(gè)系統(tǒng)運(yùn)行過(guò)程中,回收站一直維護(hù)著僅有的一個(gè)實(shí)例。
4.網(wǎng)站的計(jì)數(shù)器,一般也是采用單例模式實(shí)現(xiàn),否則難以同步。
5.應(yīng)用程序的日志應(yīng)用,一般都何用單例模式實(shí)現(xiàn),這一般是由于共享的日志文件一直處于打開(kāi)狀態(tài),因?yàn)橹荒苡幸粋€(gè)實(shí)例去操作,否則內(nèi)容不好追加。
6.Web應(yīng)用的配置對(duì)象的讀取,一般也應(yīng)用單例模式,這個(gè)是由于配置文件是共享的資源。
7.數(shù)據(jù)庫(kù)連接池的設(shè)計(jì)一般也是采用單例模式,因?yàn)閿?shù)據(jù)庫(kù)連接是一種數(shù)據(jù)庫(kù)資源。數(shù)據(jù)庫(kù)軟件系統(tǒng)中使用數(shù)據(jù)庫(kù)連接池,主要是節(jié)省打開(kāi)或者關(guān)閉數(shù)據(jù)庫(kù)連接所引起的效率損耗,這種效率上的損耗還是非常昂貴的,因?yàn)楹斡脝卫J絹?lái)維護(hù),就可以大大降低這種損耗。
8.多線(xiàn)程的線(xiàn)程池的設(shè)計(jì)一般也是采用單例模式,這是由于線(xiàn)程池要方便對(duì)池中的線(xiàn)程進(jìn)行控制。
9.操作系統(tǒng)的文件系統(tǒng),也是大的單例模式實(shí)現(xiàn)的具體例子,一個(gè)操作系統(tǒng)只能有一個(gè)文件系統(tǒng)。
10.HttpApplication也是單位例的典型應(yīng)用。熟悉ASP.Net(IIS)的整個(gè)請(qǐng)求生命周期的人應(yīng)該知道HttpApplication也是單例模式,所有的HttpModule都共享一個(gè)HttpApplication實(shí)例.
2.策略模式:
實(shí)現(xiàn)方式:
a.提供公共接口或抽象類(lèi),定義需要使用的策略方法。(策略抽象類(lèi))
b.多個(gè)實(shí)現(xiàn)的策略抽象類(lèi)的實(shí)現(xiàn)類(lèi)。(策略實(shí)現(xiàn)類(lèi))
c.環(huán)境類(lèi),對(duì)多個(gè)實(shí)現(xiàn)類(lèi)的封裝,提供接口類(lèi)型的成員量,可以在客戶(hù)端中切換。
d.客戶(hù)端調(diào)用環(huán)境類(lèi)進(jìn)行不同策略的切換。
注:Jdk中的TreeSet和TreeMap的排序功能就是使用了策略模式。
優(yōu)點(diǎn):
1.策略模式提供了管理相關(guān)的算法族的辦法。策略類(lèi)的等級(jí)結(jié)構(gòu)定義了一個(gè)算法或行為族。恰當(dāng)使用繼承可以把公共的代碼移到父類(lèi)里面,從而避免代碼重復(fù)。
2.使用策略模式可以避免使用多重條件(if-else.語(yǔ)句。多重條件語(yǔ)句不易維護(hù),它把采取哪一種算法或采取哪一種行為的邏輯與算法或行為的邏輯混合在一起,統(tǒng)統(tǒng)列在一個(gè)多重條件語(yǔ)句里面,比使用繼承的辦法還要原始和落后。
缺點(diǎn):
1.客戶(hù)端必須知道所有的策略類(lèi),并自行決定使用哪一個(gè)策略類(lèi)。這就意味著客戶(hù)端必須理解這些算法的區(qū)別,以便適時(shí)選擇恰當(dāng)?shù)乃惴?lèi)。換言之,策略模式只適用于客戶(hù)端知道算法或行為的情況。
2.由于策略模式把每個(gè)具體的策略實(shí)現(xiàn)都單獨(dú)封裝成為類(lèi),如果備選的策略很多的話(huà),那么對(duì)象的數(shù)目就會(huì)很可觀。
3.代理模式:(一)靜態(tài)代理
實(shí)現(xiàn)方式:
a.為真實(shí)類(lèi)和代理類(lèi)提供的公共接口或抽象類(lèi)。(租房)
b.真實(shí)類(lèi),具體實(shí)現(xiàn)邏輯,實(shí)現(xiàn)或繼承a。(房主向外租房)
c.代理類(lèi),實(shí)現(xiàn)或繼承a,有對(duì)b的引用,調(diào)用真實(shí)類(lèi)的具體實(shí)現(xiàn)。(中介)
d.客戶(hù)端,調(diào)用代理類(lèi)實(shí)現(xiàn)對(duì)真實(shí)類(lèi)的調(diào)用。(租客租房)
(二)動(dòng)態(tài)代理
實(shí)現(xiàn)方式:
a.公共的接口(必須是接口,因?yàn)镻roxy類(lèi)的newproxyinstance方法的第二參數(shù)必須是個(gè)接口類(lèi)型的Class)
b.多個(gè)真實(shí)類(lèi),具體實(shí)現(xiàn)的業(yè)務(wù)邏輯。
c.代理類(lèi),實(shí)現(xiàn)InvocationHandler接口,提供Object成員變量,和Set方法,便于客戶(hù)端切換。
d.客戶(hù)端,獲得代理類(lèi)的實(shí)例,為object實(shí)例賦值,調(diào)用Proxy.newproxyinstance方法在程序運(yùn)行時(shí)生成繼承公共接口的實(shí)例,調(diào)用相應(yīng)方法,此時(shí)方法的執(zhí)行由代理類(lèi)實(shí)現(xiàn)的Invoke方法接管。
jdk動(dòng)態(tài)代理使用的局限性:
通過(guò)反射類(lèi)Proxy和InvocationHandler回調(diào)接口實(shí)現(xiàn)的jdk動(dòng)態(tài)代理,要求委托類(lèi)必須實(shí)現(xiàn)一個(gè)接口,但事實(shí)上并不是所有類(lèi)都有接口,對(duì)于沒(méi)有實(shí)現(xiàn)接口的類(lèi),便無(wú)法使用該方方式實(shí)現(xiàn)動(dòng)態(tài)代理。
4.觀察者模式:
觀察者模式是對(duì)象的行為模式,又叫發(fā)布-訂閱(Publish/Subscribe.模式、模型-視圖(Model/View.模式、源-監(jiān)聽(tīng)器(Source/Listener.模式或從屬者(Dependents.模式。
實(shí)現(xiàn)方式:
a.角色抽象類(lèi)(提供對(duì)觀察者的添加,刪除和通知功能)。
b.角色具體類(lèi),實(shí)現(xiàn)a,維護(hù)一個(gè)c的集合(對(duì)角色抽象類(lèi)的實(shí)現(xiàn))。
c.觀察者抽象類(lèi)(被角色通知后實(shí)現(xiàn)的方法)。
d.觀察者實(shí)現(xiàn)類(lèi),實(shí)現(xiàn)c(多個(gè))。
注:JDK提供了對(duì)觀察者模式的支持,使用Observable類(lèi)和Observer接口
兩種模型(推模型和拉模型):
■推模型是假定主題對(duì)象知道觀察者需要的數(shù)據(jù);而拉模型是主題對(duì)象不知道觀察者具體需要什么數(shù)據(jù),沒(méi)有辦法的情況下,干脆把自身傳遞給觀察者,讓觀察者自己去按需要取值。
■推模型可能會(huì)使得觀察者對(duì)象難以復(fù)用,因?yàn)橛^察者的update()方法是按需要定義的參數(shù),可能無(wú)法兼顧沒(méi)有考慮到的使用情況。這就意味著出現(xiàn)新情況的時(shí)候,就可能提供新的update()方法,或者是干脆重新實(shí)現(xiàn)觀察者;而拉模型就不會(huì)造成這樣的情況,因?yàn)槔P拖拢瑄pdate()方法的參數(shù)是主題對(duì)象本身,這基本上是主題對(duì)象能傳遞的最大數(shù)據(jù)集合了,基本上可以適應(yīng)各種情況的需要。
5.裝飾模式:
實(shí)現(xiàn)方式:
a.抽象的被裝飾角色(所有的角色都要直接或間接的實(shí)現(xiàn)本角色)
b.具體的被裝飾角色,實(shí)現(xiàn)或繼承a(被功能擴(kuò)展的角色)
c.裝飾角色,實(shí)現(xiàn)或繼承a(本類(lèi)有對(duì)a的引用,所有的具體裝飾角色都需要繼承這個(gè)角色)
d.多個(gè)具體修飾角色,繼承c(對(duì)被裝飾角色的功能擴(kuò)展,可以任意搭配使用)
意圖:
動(dòng)態(tài)地給一個(gè)對(duì)象添加一些額外的職責(zé)。就增加功能來(lái)說(shuō),Decorator模式相比生成子類(lèi)更為靈活。該模式以對(duì)客戶(hù)端透明的方式擴(kuò)展對(duì)象的功能。
適用環(huán)境:
1.在不影響其他對(duì)象的情況下,以動(dòng)態(tài)、透明的方式給單個(gè)對(duì)象添加職責(zé)。
2.處理那些可以撤消的職責(zé)。
3.當(dāng)不能采用生成子類(lèi)的方法進(jìn)行擴(kuò)充時(shí)。一種情況是,可能有大量獨(dú)立的擴(kuò)展,為支持每一種組合將產(chǎn)生大量的子類(lèi),使得子類(lèi)數(shù)目呈爆炸性增長(zhǎng)。另一種情況可能是因?yàn)轭?lèi)定義被隱藏,或類(lèi)定義不能用于生成子類(lèi)。
6.適配器模式:
適配器模式把一個(gè)類(lèi)的接口變換成客戶(hù)端所期待的另一種接口,從而使原本因接口不匹配而無(wú)法在一起工作的兩個(gè)類(lèi)能夠在一起工作。
1.類(lèi)適配器(子類(lèi)繼承方式)
實(shí)現(xiàn)方式:
a.目標(biāo)抽象角色(定義客戶(hù)要用的接口)
b.適配器(實(shí)現(xiàn)a繼承c,作為一個(gè)轉(zhuǎn)換器被客戶(hù)調(diào)用)
c.待適配器(真正需要被調(diào)用的)
d.客戶(hù)端(借用a的實(shí)例調(diào)用c的方法)
2.對(duì)象適配器(對(duì)象的組合方式)
實(shí)現(xiàn)方式:
a.目標(biāo)抽象角色(定義客戶(hù)要用的接口)
b.適配器(實(shí)現(xiàn)a,維護(hù)一個(gè)c的引用,作為一個(gè)轉(zhuǎn)換器被d調(diào)用)
c.待適配器(真正需要被調(diào)用的)
d.客戶(hù)端(此類(lèi),借用a類(lèi)的實(shí)例調(diào)用c類(lèi)的方法,類(lèi)似靜態(tài)代理,但是解決的問(wèn)題不同)
3.缺省的方式
實(shí)現(xiàn)方式:
a.抽象接口
b.實(shí)現(xiàn)a的適配器類(lèi)(空實(shí)現(xiàn))
c.客戶(hù)端,繼承b,調(diào)用b中的方法,不必直接實(shí)現(xiàn)a(直接實(shí)現(xiàn)a需要實(shí)現(xiàn)a中的所有的方法)
優(yōu)點(diǎn):
1.更好的復(fù)用性
系統(tǒng)需要使用現(xiàn)有的類(lèi),而此類(lèi)的接口不符合系統(tǒng)的需要。那么通過(guò)適配器模式就可以讓這些功能得到更好的復(fù)用。
2.更好的擴(kuò)展性
在實(shí)現(xiàn)適配器功能的時(shí)候,可以調(diào)用自己開(kāi)發(fā)的功能,從而自然地?cái)U(kuò)展系統(tǒng)的功能。
?
缺點(diǎn):
過(guò)多的使用適配器,會(huì)讓系統(tǒng)非常零亂,不易整體進(jìn)行把握。比如,明明看到調(diào)用的是A接口,其實(shí)內(nèi)部被適配成了B接口的實(shí)現(xiàn),一個(gè)系統(tǒng)如果太多出現(xiàn)這種情況,無(wú)異于一場(chǎng)災(zāi)難。因此如果不是很有必要,可以不使用適配器,而是直接對(duì)系統(tǒng)進(jìn)行重構(gòu)。
7.命令模式
將一個(gè)請(qǐng)求封裝為一個(gè)對(duì)象,從而可用不同的請(qǐng)求對(duì)客戶(hù)進(jìn)行參數(shù)化;對(duì)請(qǐng)求排隊(duì)或記錄日志,以及支持可撤銷(xiāo)的操作
將“發(fā)出請(qǐng)求的對(duì)象”和”接收與執(zhí)行這些請(qǐng)求的對(duì)象”分隔開(kāi)來(lái)。
實(shí)現(xiàn)方式:
a.抽象的命令角色,如:菜單(規(guī)定可以點(diǎn)哪些菜)
b.具體的命令角色(實(shí)現(xiàn)a維護(hù)一個(gè)對(duì)c的引用),如:訂單(已點(diǎn)的菜)
c.接收者(具體執(zhí)行命令的角色),實(shí)際操作時(shí),很常見(jiàn)使用"聰明"命令對(duì)象,也就是直接實(shí)現(xiàn)了請(qǐng)求,而不是將工作委托給c(弊端?)如:廚師接收訂單后做菜
d.調(diào)用者(維護(hù)一個(gè)對(duì)a的引用),如:服務(wù)員負(fù)責(zé)點(diǎn)菜并把訂單推給廚師
e.客戶(hù)端調(diào)用d發(fā)出命令進(jìn)而執(zhí)行c的方法,如:顧客點(diǎn)餐
效果:
1)、command模式將調(diào)用操作的對(duì)象和實(shí)現(xiàn)該操作的對(duì)象解耦
2)、可以將多個(gè)命令裝配成一個(gè)復(fù)合命令,復(fù)合命令是Composite模式的一個(gè)實(shí)例
3)、增加新的command很容易,無(wú)需改變已有的類(lèi)
適用性:
1)、抽象出待執(zhí)行的動(dòng)作以參數(shù)化某對(duì)象
2)、在不同的時(shí)刻指定、排列和執(zhí)行請(qǐng)求。如請(qǐng)求隊(duì)列
3)、支持取消操作
4)、支持修改日志
5)、用構(gòu)建在原語(yǔ)操作上的高層操作構(gòu)造一個(gè)系統(tǒng)。支持事物
8.組合模式
將對(duì)象組合成樹(shù)形結(jié)構(gòu)以表示“部分整體”的層次結(jié)構(gòu)。組合模式使得用戶(hù)對(duì)單個(gè)對(duì)象和復(fù)雜對(duì)象的使用具有一致性。
實(shí)現(xiàn)方式:
a.抽象的構(gòu)件接口(規(guī)范執(zhí)行的方法),b及c都需實(shí)現(xiàn)此接口,如:Junit中的Test接口
b.葉部件(實(shí)現(xiàn)a,最小的執(zhí)行單位),如:Junit中我們所編寫(xiě)的測(cè)試用例
c.組合類(lèi)(實(shí)現(xiàn)a并維護(hù)一個(gè)a的集合[多個(gè)b的組合]),如:Junit中的TestSuite
d.客戶(hù)端可以隨意的將b和c進(jìn)行組合,進(jìn)行調(diào)用
什么情況下使用組合模式:
當(dāng)發(fā)現(xiàn)需求中是體現(xiàn)部分與整體層次結(jié)構(gòu)時(shí),以及你希望用戶(hù)可以忽略組合對(duì)象與單個(gè)對(duì)象的不同,統(tǒng)一地使用組合結(jié)構(gòu)中的所有對(duì)象時(shí),就應(yīng)該考慮組合模式了。
9.簡(jiǎn)單工廠(chǎng)模式
就是建立一個(gè)工廠(chǎng)類(lèi),對(duì)實(shí)現(xiàn)了同一接口的一些類(lèi)進(jìn)行實(shí)例的創(chuàng)建。簡(jiǎn)單工廠(chǎng)模式的實(shí)質(zhì)是由一個(gè)工廠(chǎng)類(lèi)根據(jù)傳入的參數(shù),動(dòng)態(tài)決定應(yīng)該創(chuàng)建哪一個(gè)產(chǎn)品類(lèi)(這些產(chǎn)品類(lèi)繼承自一個(gè)父類(lèi)或接口)的實(shí)例。
實(shí)現(xiàn)方式:
a.抽象產(chǎn)品類(lèi)(也可以是接口)
b.多個(gè)具體的產(chǎn)品類(lèi)
c.工廠(chǎng)類(lèi)(包括創(chuàng)建a的實(shí)例的方法)
優(yōu)點(diǎn):
工廠(chǎng)類(lèi)是整個(gè)模式的關(guān)鍵.包含了必要的邏輯判斷,根據(jù)外界給定的信息,決定究竟應(yīng)該創(chuàng)建哪個(gè)具體類(lèi)的對(duì)象.通過(guò)使用工廠(chǎng)類(lèi),外界可以從直接創(chuàng)建具體產(chǎn)品對(duì)象的尷尬局面擺脫出來(lái),僅僅需要負(fù)責(zé)“消費(fèi)”對(duì)象就可以了。而不必管這些對(duì)象究竟如何創(chuàng)建及如何組織的.明確了各自的職責(zé)和權(quán)利,有利于整個(gè)軟件體系結(jié)構(gòu)的優(yōu)化。
缺點(diǎn):
由于工廠(chǎng)類(lèi)集中了所有實(shí)例的創(chuàng)建邏輯,違反了高內(nèi)聚責(zé)任分配原則,將全部創(chuàng)建邏輯集中到了一個(gè)工廠(chǎng)類(lèi)中;它所能創(chuàng)建的類(lèi)只能是事先考慮到的,如果需要添加新的類(lèi),則就需要改變工廠(chǎng)類(lèi)了。當(dāng)系統(tǒng)中的具體產(chǎn)品類(lèi)不斷增多時(shí)候,可能會(huì)出現(xiàn)要求工廠(chǎng)類(lèi)根據(jù)不同條件創(chuàng)建不同實(shí)例的需求.這種對(duì)條件的判斷和對(duì)具體產(chǎn)品類(lèi)型的判斷交錯(cuò)在一起,很難避免模塊功能的蔓延,對(duì)系統(tǒng)的維護(hù)和擴(kuò)展非常不利;
10.模板方法模式
實(shí)現(xiàn)方式:
a.父類(lèi)模板類(lèi)(規(guī)定要執(zhí)行的方法和順序,只關(guān)心方法的定義及順序,不關(guān)心方法實(shí)現(xiàn))
b.子類(lèi)實(shí)現(xiàn)類(lèi)(實(shí)現(xiàn)a規(guī)定要執(zhí)行的方法,只關(guān)心方法實(shí)現(xiàn),不關(guān)心調(diào)用順序)
優(yōu)點(diǎn):
1.封裝不變部分,擴(kuò)展可變部分:把認(rèn)為不變部分的算法封裝到父類(lèi)實(shí)現(xiàn),可變部分則可以通過(guò)繼承來(lái)實(shí)現(xiàn),很容易擴(kuò)展。
2.提取公共部分代碼,便于維護(hù)。
3.行為由父類(lèi)控制,由子類(lèi)實(shí)現(xiàn)。
缺點(diǎn):
模板方法模式顛倒了我們平常的設(shè)計(jì)習(xí)慣:抽象類(lèi)負(fù)責(zé)聲明最抽象、最一般的事物屬性和方法,實(shí)現(xiàn)類(lèi)實(shí)現(xiàn)具體的事物屬性和方法。在復(fù)雜的項(xiàng)目中可能會(huì)帶來(lái)代碼閱讀的難度。