莊周夢蝶

          生活、程序、未來
             :: 首頁 ::  ::  :: 聚合  :: 管理
              其實我這系列小文,名為源碼分析,其實是自己讀《設計模式》的讀書筆記。Decorator模式在java的IO庫中得到應用,java的IO庫看起來復雜,其實理解了Decorator模式再回頭看可以很好理解并使用。
              Decorator模式,也就是裝飾器模式,是對象結構型模式之一。

          1.意圖:動態(tài)地給一個對象添加一些額外的職責。給對象添加功能,我們首先想到的是繼承,但是如果每增一個功能都需要繼承,類的繼承體系將無可避免地變的龐大和難以理解。面向對象設計的原則:優(yōu)先使用組合,而非繼承,繼承的層次深度最好不過三。

          2.適用場景:
          1)在不影響其他對象的情況下,以動態(tài)、透明的方式給單個對象添加額外的責任
          2)處理可以撤銷的職責
          3)為了避免類的數(shù)目爆炸,或者不能采用生成子類的方法進行擴展時

          3.UML圖和協(xié)作:



          Component——定義一個對象接口,可以給這些對象動態(tài)地添加職責

          ConcreteComponent——定義一個對象,可以給這個對象添加職責

          Decorator——維持一個指向Component的引用,并定義一個與Component一致的接口,作為裝飾類的父類

          ConcreteDecorator——具體裝飾類

          4.效果:
          1)與靜態(tài)繼承相比,Decorator可以動態(tài)添加職責,更為靈活
          2)避免產生復雜的類,通過動態(tài)添加職責,而不是一次性提供一個萬能的接口
          3)缺點是將產生比較多的小對象,對學習上有難度,顯然,java.io就是這個問題

          我們以一個例子來實現(xiàn)Decorator模式,假設這樣一個場景:在某個應用中需要打印票據(jù),我們寫了一個PrintTicket接口,然后提供一個實現(xiàn)類(DefaultPrintTicket)實現(xiàn)打印的功能:

          package com.rubyeye.design_pattern.decorator;
          //抽象component接口
          public interface PrintTicket {
              
          public void print();
          }


          //默認實現(xiàn)類,打印票據(jù)
          package com.rubyeye.design_pattern.decorator;

          public class DefaultPrintTicket implements PrintTicket {

              
          public void print() {
                  System.out.println(
          "ticket body");
              }

          }

          OK,我們的功能已經(jīng)實現(xiàn),我們還體現(xiàn)了針對接口編程的原則,替換一個新的打印方式很靈活,但是客戶開始提需求了——人生無法避免的三件事:交稅、死亡和需求變更??蛻粢蟠蛴№撁迹闶紫认氲降氖抢^承:
          package com.rubyeye.design_pattern.decorator;

          public class AnotherPrintTicket implements PrintTicket {

              
          public void print() {
                  System.out.println(
          "ticket header");
                  System.out.println(
          "ticket body");
              }

          }

          請注意,我們這里只是簡單的示例,在實際項目中也許意味著添加一大段代碼,并且需要修改打印票據(jù)本體的功能。需求接踵而至,客戶要求添加打印頁碼,要求增加打印花紋,要求可以聯(lián)打......你的類越來越龐大,直到你看見這個類都想吐的地步!-_-。讓我們看看另一個方案,使用Decorator模式來動態(tài)地給打印增加一些功能,首先是實現(xiàn)一個Decorator,它需要保持一個到PrintTicket接口的引用:

          package com.rubyeye.design_pattern.decorator;

          public class PrintTicketDecorator implements PrintTicket {

              
          protected PrintTicket printTicket;

              
          public PrintTicketDecorator(PrintTicket printTicket) {
                  
          this.printTicket = printTicket;
              }

              
          //默認調用PrintTicket的print
              public void print() {
                  printTicket.print();
              }

          }

          然后,我們實現(xiàn)兩個具體的裝飾類——打印頁眉和頁腳:
          package com.rubyeye.design_pattern.decorator;

          public class HeaderPrintTicket extends PrintTicketDecorator {

              
          public HeaderPrintTicket(PrintTicket printTicket){
                  
          super(printTicket);
              }
              
              
          public void print() {
                  System.out.println(
          "ticket header");
                  
          super.print();
              }
          }

          package com.rubyeye.design_pattern.decorator;

          public class FooterPrintTicket extends PrintTicketDecorator {
              
          public FooterPrintTicket(PrintTicket printTicket) {
                  
          super(printTicket);
              }

              
          public void print() {
                  
          super.print();
                  System.out.println(
          "ticket footer");
              }
          }

              使用起來也很容易:
             
          package com.rubyeye.design_pattern.decorator;

          public class DecoratorTest {

              
          /**
               * 
          @param args
               
          */
              
          public static void main(String[] args) {
                  PrintTicket print
          =new HeaderPrintTicket(new FooterPrintTicket(new DefaultPrintTicket()));
                  print.print();
              }

          }

          輸出:
          ticket header
          ticket body
          ticket footer

              了解了Decorator模式,我們聯(lián)系了下JUnit里面的應用。作為一個測試框架,應該方便地支持二次開發(fā),也許用戶開發(fā)自己的TestCase,添加自定義的功能,比如執(zhí)行重復測試、多線程測試等等。動態(tài)添加職責,而又不想使用靜態(tài)繼承,這正是Decorator使用的地方。在junit.extensions包中有一個TestDecorator,正是所有裝飾類的父類,也是作為二次開發(fā)的基礎,它實現(xiàn)了Test接口,而Test接口就是我們定義的抽象接口:
          public class TestDecorator implements  Test {
              
          //保有一個指向Test的引用
                  protected Test fTest;
                 
              
          public TestDecorator(Test test) {
                  fTest
          = test;
              }
                  
                  
          public void basicRun(TestResult result) {
                    fTest.run(result);
                  }
                  
          public void run(TestResult result) {
                     basicRun(result);
                  }
                  
          }

          Junit已經(jīng)提供了兩個裝飾類:junit.extensions.ActiveTest用于處理多線程,junit.extensions.RepeatedTest用于執(zhí)行重復測試,看看RepeatedTest是怎么實現(xiàn)的:
          public class RepeatedTest extends  TestDecorator {
                  
          //重復次數(shù)
              private int fTimesRepeat;

              
          public RepeatedTest(Test test, int repeat) {
                  
          super(test);
                  fTimesRepeat
          = repeat;
              }
                  
          public void run(TestResult result) {
                  
          //重復執(zhí)行
                          for (int i= 0; i < fTimesRepeat; i++) {
                      
          if (result.shouldStop())
                          
          break;
                      
          super.run(result);
                  }
              }
                  
          }

              RepeatedTest繼承TestDecorator ,覆寫run(TestReult result)方法,重復執(zhí)行,super.run(result)將調用傳入的TestCase的run(TestResult result)方法,這已經(jīng)在TestDecorator默認實現(xiàn)。看看使用方式,使用裝飾模式的好處不言而喻。

          TestSuite suite = new TestSuite();
          suite.addTest(
          new TestSetup(new RepeatedTest(new Testmath("testAdd"),12)));


          評論

          # re: JUnit源碼分析(四)——從Decorator模式說起  回復  更多評論   

          2007-04-06 19:17 by Jkallen
          寫得挺好的

          # re: JUnit源碼分析(四)——從Decorator模式說起  回復  更多評論   

          2009-09-10 17:15 by echozhjun
          看完四篇,很是受用。樓主辛苦了。

          # re: JUnit源碼分析(四)——從Decorator模式說起[未登錄]  回復  更多評論   

          2010-06-03 22:06 by richard
          以前看設計模式書中的裝飾模式,書中的例子好象是view和scrollview,看不出decorater 味道??戳四愕奈恼轮笥诌M一步的認識。
          主站蜘蛛池模板: 平邑县| 三门峡市| 梧州市| 绥棱县| 富裕县| 庆云县| 正镶白旗| 班玛县| 宜都市| 南郑县| 张家港市| 定兴县| 宁国市| 苗栗市| 任丘市| 东乌珠穆沁旗| 郑州市| 临高县| 大新县| 墨脱县| 江达县| 图们市| 喀喇沁旗| 朝阳县| 西藏| 米易县| 清新县| 嵊州市| 乌拉特前旗| 四平市| 久治县| 商河县| 临城县| 衡南县| 山西省| 新宁县| 攀枝花市| 宿迁市| 南京市| 筠连县| 成安县|