隨筆 - 45, 文章 - 6, 評(píng)論 - 4, 引用 - 0
          數(shù)據(jù)加載中……

          Java裝飾模式

          說(shuō)明:

                  裝飾模式是在不必改變?cè)愇募褪褂美^承的情況下,動(dòng)態(tài)的擴(kuò)展一個(gè)對(duì)象的功能。它是通過(guò)創(chuàng)建一個(gè)包裝對(duì)象,也就是裝飾來(lái)包裹真實(shí)的對(duì)象。
                  

          裝飾模式的特點(diǎn);

          (1) 裝飾對(duì)象和真實(shí)對(duì)象有相同的接口。這樣客戶端對(duì)象就可以以和真實(shí)對(duì)象相同的方式和裝飾對(duì)象交互。
          (2) 裝飾對(duì)象包含一個(gè)真實(shí)對(duì)象的索引(reference)
          (3) 裝飾對(duì)象接受所有的來(lái)自客戶端的請(qǐng)求。它把這些請(qǐng)求轉(zhuǎn)發(fā)給真實(shí)的對(duì)象。
          (4) 裝飾對(duì)象可以在轉(zhuǎn)發(fā)這些請(qǐng)求以前或以后增加一些附加功能。這樣就確保了在運(yùn)行時(shí),不用修改給定對(duì)象的結(jié)構(gòu)就可以在外部增加附加的功能。在面向?qū)ο蟮脑O(shè)計(jì)中,通常是通過(guò)繼承來(lái)實(shí)現(xiàn)對(duì)給定類的功能擴(kuò)展。

          裝飾模式 VS 繼承

           裝飾模式                                                                 繼承
          用來(lái)擴(kuò)展特定對(duì)象的功能                     用來(lái)擴(kuò)展一類對(duì)象的功能
          不需要子類                                             需要子類
          動(dòng)態(tài)地                                                     靜態(tài)地
          運(yùn)行時(shí)分配職責(zé)                                     編譯時(shí)分派職責(zé)
          防止由于子類而導(dǎo)致的復(fù)雜和混亂     導(dǎo)致很多子類產(chǎn)生,在一些場(chǎng)合,報(bào)漏類的層次
          更多的靈活性                                         缺乏靈活性

          例子:

                  讓我們重新返回我們?cè)诠S方法和單例模式log實(shí)用工具上,我們的模式主要由Logger 接口和兩個(gè)它的實(shí)現(xiàn)類??FileLogger和ConsoleLogger??分別把信息出力到一個(gè)文件和屏幕中。另外,還有包括工廠方法的LoggerFactory類。
          LoggerFactory沒(méi)有出現(xiàn)在下圖中,主要是因?yàn)樗同F(xiàn)在討論的例子沒(méi)有直接聯(lián)系。

          讓我們想象一些客戶端需要以超出Logger Utility現(xiàn)在所提供的新的方式出力信息,客戶端需要下面兩種特征;
          (1) 把出力的信息傳喚為HTML文檔
          (2) 對(duì)出力信息進(jìn)行邏輯轉(zhuǎn)化的簡(jiǎn)單加密,在面向?qū)ο蟮脑O(shè)計(jì)中,不改變現(xiàn)存的類的代碼,可以應(yīng)用繼承來(lái)增加新的功能。例如,子類化現(xiàn)在的類重載它的方法來(lái)增加所需要的新功能。

          應(yīng)用繼承,我們要子類化FileLogger和ConsoleLogger類來(lái)增加新的功能,會(huì)有下面的一組新的子類:
          子類 父類 功能
          HTMLFileLogger FileLogger 轉(zhuǎn)化出力信息為HTML文檔,并存入一個(gè)Log文件
          HTMLConsLogger ConsoleLogger 轉(zhuǎn)化出力信息為HTML文檔,并顯示在屏幕上
          EncFileLogger FileLogger 加密出力信息,并存入一個(gè)Log文件
          EncConsLogger ConsoleLogger 加密出力信息,并顯示在屏幕上

          從類圖可以看到,為了實(shí)現(xiàn)新的功能加入了一組新的子類。如果我們還有其他的Logger類型(例如:DBLogger出力信息到數(shù)據(jù)庫(kù)中),這樣會(huì)有更多子類。當(dāng)一個(gè)新的特性需要被加入,子類的數(shù)量會(huì)有成倍數(shù)的增長(zhǎng),同時(shí)我們會(huì)有一個(gè)龐大的類層次。

          裝飾模式使我們從這種情景中解脫出來(lái),裝飾模式推薦通過(guò)對(duì)象的合成而不是繼承來(lái)包裝一個(gè)對(duì)象擴(kuò)展它的功能。
          應(yīng)用裝飾模式,讓我們?yōu)長(zhǎng)ogger Utility定義一個(gè)有下列特征的默認(rèn)根裝飾類LoggerDecorator:

          (1) LoggerDecorator包括一個(gè)Logger實(shí)例的引用。這個(gè)引用指向它包含的Logger對(duì)象。
          (2) LoggerDecorator實(shí)現(xiàn)Logger借口、提供Log方法的基本的默認(rèn)實(shí)現(xiàn),他只是簡(jiǎn)單的轉(zhuǎn)發(fā)調(diào)用給它包含的Logger 對(duì)象。每一個(gè)LoggerDecorator子類保證定義log方法。

          Listing 19.1: LoggerDecorator Class

          1. public class LoggerDecorator implements Logger {
          2. Logger logger;
          3. public LoggerDecorator(Logger inp_logger) {
          4. logger = inp_logger;
          5. }
          6. public void log(String DataLine) {
          7. /*
          8. Default implementation
          9. to be overriden by subclasses.
          10. */
          11. logger.log(DataLine);
          12. }
          13. }//end of class

          每一個(gè)logger的裝飾定義log方法使很重要的,因?yàn)檠b飾對(duì)象必須提供和它包裝的對(duì)象相同的借口。當(dāng)客戶端創(chuàng)建一個(gè)裝飾類的實(shí)例,客戶端以與裝飾類交互方式和客戶端與擁有相同接口原對(duì)象的交互方式是一致的。
          讓我們定義LoggerDecorator的兩個(gè)子類,HTMLLogger和EncryptLogger。 #p# 具體的Logger 裝飾類

          HTMLLogger

          HTMLLogger重載了log方法的默認(rèn)實(shí)現(xiàn)。在log方法中,裝飾類把出力信息轉(zhuǎn)化為HTML文檔,并且發(fā)送給可以出力的Logger實(shí)例。
          Listing 19.2: HTMLLogger Class

          1. public class HTMLLogger extends LoggerDecorator {
          2. public HTMLLogger(Logger inp_logger) {
          3. super(inp_logger);
          4. }
          5. public void log(String DataLine) {
          6. /*
          7. Added functionality
          8. */
          9. DataLine = makeHTML(DataLine);
          10. /*
          11. Now forward the encrypted text to the FileLogger
          12. for storage
          13. */
          14. logger.log(DataLine);
          15. }
          16. public String makeHTML(String DataLine) {
          17. /*
          18. Make it into an HTML document.
          19. */
          20. DataLine = "" + """ + DataLine +
          21. " + "";
          22. return DataLine;
          23. }
          24. }//end of class
          EncryptLogger

          與HTMLLogger相似,EncryptLogger重載了log方法,在log方法中,EncryptLogger通過(guò)簡(jiǎn)單的將字符位置向右轉(zhuǎn)移一位實(shí)現(xiàn)了加密邏輯,并且發(fā)送給可以出力的Logger實(shí)例。

          Listing 19.3: EncryptLogger Class

          1. public class EncryptLogger extends LoggerDecorator {
          2. public EncryptLogger(Logger inp_logger) {
          3. super(inp_logger);
          4. }
          5. public void log(String DataLine) {
          6. /*
          7. Added functionality
          8. */
          9. DataLine = encrypt(DataLine);
          10. /*
          11. Now forward the encrypted text to the FileLogger
          12. for storage
          13. */
          14. logger.log(DataLine);
          15. }
          16. public String encrypt(String DataLine) {
          17. /*
          18. Apply simple encryption by Transposition…
          19. Shift all characters by one position.
          20. */
          21. DataLine = DataLine.substring(DataLine.length() − 1) +
          22. DataLine.substring(0, DataLine.length() − 1);
          23. return DataLine;
          24. }
          25. }//end of class

          為了使用新設(shè)計(jì)裝飾對(duì)象,客戶端需要:

          (1) 使用LoggerFactory工廠方法創(chuàng)建一個(gè)合適的Logger實(shí)例(FileLogger/ConsoleLogger)。
          (2) 把第一步中創(chuàng)建的Logger實(shí)例作為參數(shù)轉(zhuǎn)遞給新創(chuàng)建的合適的LoggerDecorator實(shí)例的構(gòu)造函數(shù)。
          (3) 調(diào)用LoggerDecorator實(shí)例上的方法,

          Listing 19.4: Client DecoratorClient Class

          1. class DecoratorClient {
          2. public static void main(String[] args) {
          3. LoggerFactory factory = new LoggerFactory();
          4. Logger logger = factory.getLogger();
          5. HTMLLogger hLogger = new HTMLLogger(logger);
          6. //the decorator object provides the same interface.
          7. hLogger.log("A Message to Log");
          8. EncryptLogger eLogger = new EncryptLogger(logger);
          9. eLogger.log("A Message to Log");
          10. }
          11. }//End of class

          增加新的信息出力類型

          在Logging Utility實(shí)例中,應(yīng)用裝飾模式對(duì)比使用繼承不會(huì)因?yàn)轭悓哟蔚脑鲩L(zhǎng)而導(dǎo)致大量的子類,我們還有另外的Logger類型:DBLogger??出力信息到數(shù)據(jù)庫(kù)中。為了將信息轉(zhuǎn)化HTML格式或在出力到數(shù)據(jù)庫(kù)以前對(duì)信息進(jìn)行加密,客戶端只需遵從上面提到的步驟,因?yàn)镈BLogger是一種Logger類型,它可以作為構(gòu)造函數(shù)的參數(shù)傳遞給HTMLLogger或EncryptLogger中任何一個(gè)類。

          增加新的裝飾

          從例子中可以看到,LoggerDecorator實(shí)例包含了一個(gè)Logger類型了對(duì)象實(shí)例,在轉(zhuǎn)發(fā)請(qǐng)求給Logger對(duì)象實(shí)例以前或以后,增加新的功能。因?yàn)長(zhǎng)oggerDecorator類實(shí)現(xiàn)了Logger接口,LoggerDecorator實(shí)例或它的任何一個(gè)子類都可以作為一個(gè)Logger類型。因此LoggerDecortator包含它的任何子類的一個(gè)實(shí)例,并且將請(qǐng)求轉(zhuǎn)發(fā)給它/。一般的一個(gè)裝飾對(duì)象可以包含另一個(gè)裝飾對(duì)象,并且可以向它轉(zhuǎn)發(fā)請(qǐng)求。通過(guò)這種方式,新的裝飾類,新的功能可以通過(guò)包裝現(xiàn)存的裝飾類來(lái)實(shí)現(xiàn)。

          posted on 2009-11-01 10:38 liyang 閱讀(959) 評(píng)論(0)  編輯  收藏 所屬分類: design pattern


          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 思茅市| 方正县| 平昌县| 安陆市| 安化县| 铜陵市| 嵩明县| 福州市| 宾阳县| 江津市| 库车县| 东阿县| 简阳市| 佛坪县| 时尚| 喀喇沁旗| 惠东县| 深圳市| 济源市| 延津县| 涟源市| 漳州市| 方城县| 呼玛县| 长治市| 江达县| 云梦县| 喀喇沁旗| 方山县| 天全县| 青阳县| 龙里县| 汤原县| 左贡县| 宜兰市| 太和县| 政和县| 栖霞市| 东乡县| 贵阳市| 中方县|