莊周夢蝶

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

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

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

          3.UML圖和協作:



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

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

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

          ConcreteDecorator——具體裝飾類

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

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

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


          //默認實現類,打印票據
          package com.rubyeye.design_pattern.decorator;

          public class DefaultPrintTicket implements PrintTicket {

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

          }

          OK,我們的功能已經實現,我們還體現了針對接口編程的原則,替換一個新的打印方式很靈活,但是客戶開始提需求了——人生無法避免的三件事:交稅、死亡和需求變更。客戶要求打印頁眉,你首先想到的是繼承:
          package com.rubyeye.design_pattern.decorator;

          public class AnotherPrintTicket implements PrintTicket {

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

          }

          請注意,我們這里只是簡單的示例,在實際項目中也許意味著添加一大段代碼,并且需要修改打印票據本體的功能。需求接踵而至,客戶要求添加打印頁碼,要求增加打印花紋,要求可以聯打......你的類越來越龐大,直到你看見這個類都想吐的地步!-_-。讓我們看看另一個方案,使用Decorator模式來動態地給打印增加一些功能,首先是實現一個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();
              }

          }

          然后,我們實現兩個具體的裝飾類——打印頁眉和頁腳:
          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模式,我們聯系了下JUnit里面的應用。作為一個測試框架,應該方便地支持二次開發,也許用戶開發自己的TestCase,添加自定義的功能,比如執行重復測試、多線程測試等等。動態添加職責,而又不想使用靜態繼承,這正是Decorator使用的地方。在junit.extensions包中有一個TestDecorator,正是所有裝飾類的父類,也是作為二次開發的基礎,它實現了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已經提供了兩個裝飾類:junit.extensions.ActiveTest用于處理多線程,junit.extensions.RepeatedTest用于執行重復測試,看看RepeatedTest是怎么實現的:
          public class RepeatedTest extends  TestDecorator {
                  
          //重復次數
              private int fTimesRepeat;

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

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

          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 味道。看了你的文章之后又進一步的認識。
          主站蜘蛛池模板: 类乌齐县| 海淀区| 财经| 普安县| 青州市| 洛南县| 丰县| 绵竹市| 建昌县| 陆良县| 博白县| 乐平市| 古丈县| 泽普县| 克拉玛依市| 库尔勒市| 淳化县| 鹿泉市| 龙泉市| 汉阴县| 富源县| 商水县| 梅河口市| 洞头县| 丰县| 藁城市| 佛冈县| 翼城县| 山丹县| 潮安县| 新竹市| 正阳县| 阿瓦提县| 揭东县| 卢湾区| 阳西县| 房产| 深泽县| 泊头市| 宁河县| 牙克石市|