欧美三区_成人在线免费观看视频_欧美极品少妇xxxxⅹ免费视频_a级毛片免费播放_鲁一鲁中文字幕久久_亚洲一级特黄

使用設(shè)計模式改善程序結(jié)構(gòu)(二)

系統(tǒng) 1787 0

使用設(shè)計模式改善程序結(jié)構(gòu)(二)

? ? ? ? 在本系列的? 第一篇 文章中,描述了如何通過設(shè)計模式來指導我們的程序重構(gòu)過程,并且著重介紹了設(shè)計模式意圖、動機的重要性。在本文中我們將繼續(xù)上篇文章進行討論,這次主要著重于設(shè)計模式的適用性,對于設(shè)計模式適用性的掌握有助于從另一個不同的方面來判斷一個設(shè)計模式是否真正適用于我們的實際問題,從而做出明智的選擇。

1、 回顧

在上一篇文章中,我們給出了一個使用設(shè)計模式來改善程序結(jié)構(gòu)的例子,著重介紹了設(shè)計模式的意圖、動機在我們程序重構(gòu)過程中的指導作用。

現(xiàn)在,我們將關(guān)注設(shè)計模式的另一個重要方面:設(shè)計模式的適用性。解決同一個問題一般會有多種方案或者模式,但是這些模式所關(guān)注的是同一個問題的不同方面,解決不同的需求,有各自的優(yōu)點和限制,各有各的解決之道。這就要求我們在選擇設(shè)計模式時,對我們自己的問題有很好的理解:我們的需求是什么,我們要克服什么樣的限制,我們要獲得什么樣的特性等等。然后,可以看看我們想使用的解決問題的設(shè)計模式是否適用于我們的問題,如果不適用,是否可以使用其他的模式來彌補,是否可以對這個設(shè)計模式進行改進使它符合我們的要求。

本文下面的部分,我們將對上一篇文章中的最終解決方案進行進一步的分析,來看看它到底滿足了我們什么樣的需求,又暴露了什么樣的不足,最后我們會給出一個更為符合要求的解決方案。

?

2、 問題描述

在上一篇文章中,我們對一個網(wǎng)管系統(tǒng)中的錯誤處理部分的代碼進行了重構(gòu),最終使用了一個visitor設(shè)計模式解決了我們的問題。細心的讀者肯定會發(fā)現(xiàn),這個最終方案一樣存在著一個問題:如果錯誤的類型不是固定不變的,而是隨著系統(tǒng)的進展不斷增加的,會有什么結(jié)果呢?讓我們首先來看看上一篇文章中最終的類圖:

圖1

在這個類圖中,我增加了幾條依賴線,即ErrorHandler是依賴于DbError和CommError的。此時我們可以看到:ErrorBase依賴于ErrorHandler,ErrorHandler依賴于ErrorBase的派生類(DbError和CommError),而ErrorBase的派生類又要依賴于ErrorBase本身。這就形成了一個循環(huán)的依賴過程,這樣的結(jié)果就是ErrorBase傳遞地依賴于它的所有派生類。

這種循環(huán)依賴關(guān)系會帶來嚴重的問題,一旦ErrorBase新增了一個派生類,那么ErrorHandler類必須要被修改,由于ErrorBase又依賴于ErrorHandler,那么依賴于ErrorBase的所有類都需要重新編譯。這就意味著ErrorBase的所有派生類以及所有這些派生類的使用者都要重新編譯,這種大規(guī)模的重新編譯在開發(fā)一個分布式系統(tǒng)時會導致非常大的工作量,因為要重新分布每一個重新編譯過的類,如果在重新分布時出現(xiàn)一些差錯(如:忘記替換一些類),就會導致微妙的錯誤,而且很不容易查找出來。

另外,在該模式中存在一個假設(shè),就是默認任意一個錯誤處理者要處理所有的錯誤類型,這個假設(shè)在某些情況下是不成立的,比如:如果對于LogicError我們不打算通知LOGSys進行處理會怎樣呢?我們不得不要寫一個處理該錯誤的空函數(shù)(當然你可以在ErrorHandler中寫一個缺省的實現(xiàn))。如果ErrorBase的類層次架構(gòu)越來越大,并且它們要求的處理方法也有很多的不同,就會導致ErrorHandler接口中的方法集龐大,并且任何一個ErrorBase的派生類的改變,都會導致大規(guī)模的重新編譯(甚至是毫無關(guān)系的類也要重新編譯),重新分布,如果這種改變比較頻繁,結(jié)果當然是無法忍受的。

?

3、 問題分析

上述的問題描述暴露了visitor模式的一些使用限制,即它僅僅適用于哪些受訪問的類層次架構(gòu)比較固定的情況,導致這樣的原因可以使用一個著名的面向?qū)ο笤O(shè)計原則來解釋,這個原則就是:DIP(Dependence Inversion Principle),這個原則的核心含義是:高層模塊不應該直接依賴于低層模塊,所有的模塊都要依賴于抽象。也就是說:容易變化的東西一定要依賴于不容易變化的東西,因為抽象的東西最不容易變化,具體的東西容易變化,所以具體應該依賴于抽象。而在visitor模式中,ErrorHandler依賴于ErrorBase的所有的具體的派生類,并且如果這些派生類容易變化的話,就會導致不能接受的結(jié)果。

通過上面的分析,可以看出打斷這個循環(huán)依賴的環(huán)是克服visitor模式適用范圍限制的關(guān)鍵。

?

4、 解決方案

在上述的循環(huán)依賴關(guān)系中,有兩段依賴關(guān)系是無法打斷的,一段是ErrorBase的所有派生類對于ErrorBase的依賴,一段是ErrorBase對于ErrorHandler的依賴,并且這兩段依賴關(guān)系也是符合DIP的,那么對于僅剩的一段依賴關(guān)系我們是必須要打斷的了,這段關(guān)系就是,ErrorHandler對于ErrorBase所有派生類的依賴,并且這段關(guān)系也是違反DIP的。如果我們不讓ErrorHandler知道ErrorBase的派生類,那么怎樣才能夠針對每一個具體的ErrorBase的派生類進行相應的處理呢?

面向?qū)ο蟠髱烺obert C. Martin給出了一個優(yōu)雅的解決方案,他所采用的技巧是OO方法所建議避免使用的,RTTI(運行時類型鑒別)。可見如果RTTI運用的得當,一樣可以得到很好的設(shè)計方案,并且還能夠克服一些OO中多態(tài)的方法解決不了的問題(當然如果使用多態(tài)能夠解決的問題,推薦還是使用多態(tài)的方法進行解決)。讓我們先看看這個解決方案的類圖:

圖2

通過上圖可以看出,ErrorHandler中沒有任何方法了,已經(jīng)退化為一個空的接口,所以也就不可能再依賴于任何ErrorBase的派生類了。和visitor模式不同,這個方案中針對每一個特定的ErrorBase的派生類定義一個相應的處理接口,在每個派生類的handle方法實現(xiàn)中,運用RTTI技術(shù)進行相應的類型轉(zhuǎn)換(把ErrorHandler轉(zhuǎn)換為自己對應的錯誤處理接口,比如:在DbError的handle方法中,就把ErrorHandler轉(zhuǎn)換為DbErrorHandler。Java在這方面做得不錯,可以進行比較安全的類型轉(zhuǎn)換),想要處理該錯誤的實體不僅要實現(xiàn)ErrorHandler接口,而且還要實現(xiàn)相應的針對具體錯誤類的處理接口,比如:GUISys就實現(xiàn)了三個接口(ErrorHandler、DBErrorHandler以及CommErrorHandler),從而也就實現(xiàn)了對DbError和CommError的處理。

這種方法打斷了類之間的循環(huán)依賴關(guān)系,使得增加新的錯誤類型變得容易,并且也避免了可能出現(xiàn)的大規(guī)模的重新編譯以及類的重新分布。并且,你也可以有選擇地進行錯誤的處理,比如:如果GUISys不想處理DbError的話,很簡單,不要實現(xiàn)DbErrorHandler接口即可,使得程序的結(jié)構(gòu)非常清晰。可見這個方案克服了原始的visitor設(shè)計模式的不足。

通過對比上下兩個類圖可以看出,下面的要比上面的復雜,這也是該方案的一個缺點。如果問題的規(guī)模不大,重新編譯以及重新分布沒有多少工作量的話,還是可以使用原始的visitor模式的。僅僅當問題的規(guī)模擴大到visitor模式不能適用的地步時,可以考慮使用該方案。另外,由于改進的方案中使用了RTTI技術(shù),會導致性能上的損失以及不可預測性,在使用時也要特別注意。

我們做如下的類比以便于更好地理解原始的visitor模式和改進后的方案。原始的visitor模式好像一個矩陣,在X方向上是一個個具體的錯誤類型,在Y方向上是一個個可以處理錯誤的實體,每一個交叉點上是具體的處理方法,矩陣中的每一個位置上都必須有一個處理方法。而改進后的方案象一個稀疏矩陣,僅僅在需要的位置上才有具體的處理方法,從而減少了很多冗余。

下面給出關(guān)鍵的代碼片斷:

        interface ErrorBase
{
    public void handle(ErrorHandler handler);
}
class DBError implements ErrorBase
{
    public void handle(ErrorHandler handler) {
        try {
            DbErrorHandler dbHandler = (DbErrorHandler)handler;
            dbHandler.handle(this);
        }
        catch(ClassCastException e) {
        }
    }
}
class CommError implements ErrorBase
{
    public void handle(ErrorHandler handler) {
        try {
            CommErrorHandler commHandler = (CommErrorHandler)handler;
            commHandler.handle(this);
        }
        catch(ClassCastException e)\ {
        }
    }
}
interface ErrorHandler 
{
}
interface DbErrorHandler
{
    public void handle(DBrror dbError);
}
interface CommErrorHandler
{
    public void handle(CommError commError);
}
class GUISys implements ErrorHandler, DbErrorHandler, CommErrorHandler
{
    public void announceError(ErrorBase error) {
        error.handle(this);
    }
    public void handle(DBError dbError) {
 		/* 通知用戶界面進行有關(guān)數(shù)據(jù)庫錯誤的處理 */       
    }
    public void handle(CommError commError) {
    		/* 通知用戶界面進行有關(guān)通信錯誤的處理 */       
    }
}
class LogSys implements ErrorHandler, DbErrorHandler, CommErrorHandler
{
    public void announceError(ErrorBase error) {
        error.handle(this);
    }
    public void handle(DBError dbError) {
        		/* 通知日志系統(tǒng)進行有關(guān)數(shù)據(jù)庫錯誤的處理 */       
    }
    public void handle(CommError commError) {
		/* 通知日志系統(tǒng)進行有關(guān)通信錯誤的處理 */       
    }
}
      
?

5、 結(jié)論

本文從另一個方面,設(shè)計模式的適用性,探討了在進行程序重構(gòu)時該如何選擇重構(gòu)的目標,以及如何對現(xiàn)有的設(shè)計模式進行改進使之符合我們的目標。本文的主要目的是想說明,在進行設(shè)計模式的選擇時,不僅要關(guān)注設(shè)計模式是解決什么問題的,還要關(guān)注使用該設(shè)計模式解決問題時會受到什么約束和限制。這樣就可以幫助你更好地理解問題,做出合理的取舍,或者你可以根據(jù)自己的需求對已有的設(shè)計模式進行修改使之滿足你的要求,如果你這樣做了,你就很可能創(chuàng)造出了一種新的設(shè)計模式。

使用設(shè)計模式改善程序結(jié)構(gòu)(二)


更多文章、技術(shù)交流、商務合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 国产亚洲精品久久久久久老妇 | 天天摸天天碰天天碰 | 九九久久精品 | 免费高清seyeye在线视频观看 | 亚洲ci网| 三级在线观看视频 | 欧美第一页草草影院浮力 | 欧美手机在线观看 | 亚洲免费在线看 | 国产成人不卡 | 啪啪免费视频网站 | 蜜桃精品导航 | 99精品视频免费在线观看 | 永久精品 | 天天噜日日噜夜夜噜 | 亚洲欧美日本在线观看 | 国产视频高清在线 | 色狠狠狠色噜噜噜综合网 | WWW.亚洲最大夜色伊人 | 污视频免费观看网站 | 福利影院在线看 | 天天看天天摸色天天综合网 | 国产黄三级三·级三级 | 欧美精品久久久久久久久老牛影院 | 一本一道久久a久久精品蜜桃 | 成人免费在线 | 亚洲刺激视频 | 亚洲国产精品第一区二区三区 | 久久人人爽人人爽人人 | 美女在线视频网站 | 国产一级大片在线观看 | 国产精品专区第1页 | 国产精品国产成人国产三级 | 国模无水印一区二区三区 | 久国产精品 | 日本高清视频在线播放 | 久久久久久久影院 | 久久99精品视频 | 欧美日韩亚洲在线 | jiaduolu| 亚洲区视频 |