小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

裝飾模式(Decorator Pattern)

 漂在北方的狼 2007-03-28

一、 裝飾(Decorator)模式

裝飾(Decorator)模式又名包裝(Wrapper)模式[GOF95]。裝飾模式以對客戶端透明的方式擴(kuò)展對象的功能,是繼承關(guān)系的一個替代方案。

引言

孫悟空有七十二般變化,他的每一種變化都給他帶來一種附加的本領(lǐng)。他變成魚兒時,就可以到水里游泳;他變成雀兒時,就可以在天上飛行。而不管悟空怎么變化,在二郎神眼里,他永遠(yuǎn)是那只猢猻。

裝飾模式以對客戶透明的方式動態(tài)地給一個對象附加上更多的責(zé)任。換言之,客戶端并不會覺得對象在裝飾前和裝飾后有什么不同。裝飾模式可以在不使用創(chuàng)造更多子類的情況下,將對象的功能加以擴(kuò)展。


二、 裝飾模式的結(jié)構(gòu)

裝飾模式使用原來被裝飾的類的一個子類的實例,把客戶端的調(diào)用委派到被裝飾類。裝飾模式的關(guān)鍵在于這種擴(kuò)展是完全透明的。

在孫猴子的例子里,老孫變成的魚兒相當(dāng)于老孫的子類,這條魚兒與外界的互動要通過"委派",交給老孫的本尊,由老孫本尊采取行動。

裝飾模式的類圖如下圖所示:

 

在裝飾模式中的各個角色有:

  • 抽象構(gòu)件(Component)角色:給出一個抽象接口,以規(guī)范準(zhǔn)備接收附加責(zé)任的對象。
  • 具體構(gòu)件(Concrete Component)角色:定義一個將要接收附加責(zé)任的類。
  • 裝飾(Decorator)角色:持有一個構(gòu)件(Component)對象的實例,并定義一個與抽象構(gòu)件接口一致的接口。
  • 具體裝飾(Concrete Decorator)角色:負(fù)責(zé)給構(gòu)件對象"貼上"附加的責(zé)任。


三、 裝飾模式示例性代碼

以下示例性代碼實現(xiàn)了裝飾模式:

 

// Decorator pattern -- Structural example  
using System;

// "Component"
abstract class Component
{
  
// Methods
  abstract public void Operation();
}


// "ConcreteComponent"
class ConcreteComponent : Component
{
  
// Methods
  override public void Operation()
  
{
    Console.WriteLine(
"ConcreteComponent.Operation()");
  }

}


// "Decorator"
abstract class Decorator : Component
{
  
// Fields
  protected Component component;

  
// Methods
  public void SetComponent( Component component )
  
{
    
this.component = component;
  }


  
override public void Operation()
  
{
    
if( component != null )
      component.Operation();
  }

}


// "ConcreteDecoratorA"
class ConcreteDecoratorA : Decorator
{
  
// Fields
  private string addedState;

  
// Methods
  override public void Operation()
  
{
    
base.Operation();
    addedState 
= "new state";
    Console.WriteLine(
"ConcreteDecoratorA.Operation()");
  }

}


// "ConcreteDecoratorB"
class ConcreteDecoratorB : Decorator
{
  
// Methods
  override public void Operation()
  
{
    
base.Operation();
    AddedBehavior();
    Console.WriteLine(
"ConcreteDecoratorB.Operation()");
  }


  
void AddedBehavior()
  
{
  }

}


/// 
/// Client test
/// 

public class Client
{
  
public static void Main( string[] args )
  
{
    
// Create ConcreteComponent and two Decorators
    ConcreteComponent c = new ConcreteComponent();
    ConcreteDecoratorA d1 
= new ConcreteDecoratorA();
    ConcreteDecoratorB d2 
= new ConcreteDecoratorB();

    
// Link decorators
    d1.SetComponent( c );
    d2.SetComponent( d1 );

    d2.Operation();
  }

}

 

上面的代碼在執(zhí)行裝飾時是通過SetComponent方法實現(xiàn)的,在實際應(yīng)用中,也有通過構(gòu)造函數(shù)實現(xiàn)的,一個典型的創(chuàng)建過程可能如下:

 

new Decorator1(
   
new Decorator2(
      
new Decorator3(
         
new ConcreteComponent()
         )
      )
   )

 

裝飾模式常常被稱為包裹模式,就是因為每一個具體裝飾類都將下一個具體裝飾類或者具體構(gòu)件類包裹起來。


四、 裝飾模式應(yīng)當(dāng)在什么情況下使用

在以下情況下應(yīng)當(dāng)使用裝飾模式:

  1. 需要擴(kuò)展一個類的功能,或給一個類增加附加責(zé)任。
  2. 需要動態(tài)地給一個對象增加功能,這些功能可以再動態(tài)地撤銷。
  3. 需要增加由一些基本功能的排列組合而產(chǎn)生的非常大量的功能,從而使繼承關(guān)系變得不現(xiàn)實。

五、 裝飾模式實際應(yīng)用的例子

該例子演示了通過裝飾模式為圖書館的圖書與錄像帶添加"可借閱"裝飾。

 

// Decorator pattern -- Real World example  
using System;
using System.Collections;

// "Component"
abstract class LibraryItem
{
  
// Fields
  private int numCopies;

  
// Properties
  public int NumCopies
  
{
    
getreturn numCopies; }
    
set{ numCopies = value; }
  }


  
// Methods
  public abstract void Display();
}


// "ConcreteComponent"
class Book : LibraryItem
{
  
// Fields
  private string author;
  
private string title;

  
// Constructors
  public Book(string author,string title,int numCopies)
  
{
    
this.author = author;
    
this.title = title;
    
this.NumCopies = numCopies;
  }


  
// Methods
  public override void Display()
  
{
    Console.WriteLine( 
" Book ------ " );
    Console.WriteLine( 
" Author: {0}", author );
    Console.WriteLine( 
" Title: {0}", title );
    Console.WriteLine( 
" # Copies: {0}", NumCopies );
  }

}


// "ConcreteComponent"
class Video : LibraryItem
{
  
// Fields
  private string director;
  
private string title;
  
private int playTime;

  
// Constructor
  public Video( string director, string title,
    
int numCopies, int playTime )
  
{
    
this.director = director;
    
this.title = title;
    
this.NumCopies = numCopies;
    
this.playTime = playTime;
  }


  
// Methods
  public override void Display()
  
{
    Console.WriteLine( 
" Video ----- " );
    Console.WriteLine( 
" Director: {0}", director );
    Console.WriteLine( 
" Title: {0}", title );
    Console.WriteLine( 
" # Copies: {0}", NumCopies );
    Console.WriteLine( 
" Playtime: {0}", playTime );
  }

}


// "Decorator"
abstract class Decorator : LibraryItem
{
  
// Fields
  protected LibraryItem libraryItem;

  
// Constructors
  public Decorator ( LibraryItem libraryItem )
  
this.libraryItem = libraryItem; }

  
// Methods
  public override void Display()
  
{ libraryItem.Display(); }
}


// "ConcreteDecorator"
class Borrowable : Decorator
{
  
// Fields
  protected ArrayList borrowers = new ArrayList();

  
// Constructors
  public Borrowable( LibraryItem libraryItem )
    : 
base( libraryItem ) {}

  
// Methods
  public void BorrowItem( string name )
  
{
    borrowers.Add( name );
    libraryItem.NumCopies
--;
  }


  
public void ReturnItem( string name )
  
{
    borrowers.Remove( name );
    libraryItem.NumCopies
++;
  }


  
public override void Display()
  
{
    
base.Display();
    
foreachstring borrower in borrowers )
      Console.WriteLine( 
" borrower: {0}", borrower );
  }

}

 
/// 
///  DecoratorApp test
/// 

public class DecoratorApp
{
  
public static void Main( string[] args )
  
{
    
// Create book and video and display
    Book book = new Book( "Schnell""My Home"10 );
    Video video 
= new Video( "Spielberg",
      
"Schindler‘s list"2360 );
    book.Display();
    video.Display();

    
// Make video borrowable, then borrow and display
    Console.WriteLine( " Video made borrowable:" );
    Borrowable borrowvideo 
= new Borrowable( video );
    borrowvideo.BorrowItem( 
"Cindy Lopez" );
    borrowvideo.BorrowItem( 
"Samuel King" );

    borrowvideo.Display();
  }

}

 


六、 使用裝飾模式的優(yōu)點和缺點

使用裝飾模式主要有以下的優(yōu)點:

  1. 裝飾模式與繼承關(guān)系的目的都是要擴(kuò)展對象的功能,但是裝飾模式可以提供比繼承更多的靈活性。
  2. 通過使用不同的具體裝飾類以及這些裝飾類的排列組合,設(shè)計師可以創(chuàng)造出很多不同行為的組合。
  3. 這種比繼承更加靈活機動的特性,也同時意味著裝飾模式比繼承更加易于出錯。

使用裝飾模式主要有以下的缺點:

由于使用裝飾模式,可以比使用繼承關(guān)系需要較少數(shù)目的類。使用較少的類,當(dāng)然使設(shè)計比較易于進(jìn)行。但是,在另一方面,使用裝飾模式會產(chǎn)生比使用繼承關(guān)系更多的對象。更多的對象會使得查錯變得困難,特別是這些對象看上去都很相像。


七、 模式實現(xiàn)的討論

大多數(shù)情況下,裝飾模式的實現(xiàn)都比上面定義中給出的示意性實現(xiàn)要簡單。對模式進(jìn)行簡化時需要注意以下的情況:

(1)一個裝飾類的接口必須與被裝飾類的接口相容。

(2)盡量保持Component作為一個"輕"類,不要把太多的邏輯和狀態(tài)放在Component類里。

(3)如果只有一個ConcreteComponent類而沒有抽象的Component類(接口),那么Decorator類經(jīng)常可以是ConcreteComponent的一個子類。如下圖所示:

 

(4)如果只有一個ConcreteDecorator類,那么就沒有必要建立一個單獨的Decorator類,而可以把Decorator和ConcreteDecorator的責(zé)任合并成一個類。


八、 透明性的要求

透明的裝飾模式

裝飾模式通常要求針對抽象編程。裝飾模式對客戶端的透明性要求程序不要聲明一個ConcreteDecorator類型的變量,而應(yīng)當(dāng)聲明一個Component類型的變量。換言之,下面的做法是對的:

 

Component c = new ConcreteComponent();
Component c1 
= new ConcreteDecorator1(c);
Component c2 
= new ConcreteDecorator(c1);

 

而下面的做法是不對的:

 

ConcreteComponent c = new ConcreteDecorator();

 

這就是前面所說的,裝飾模式對客戶端是完全透明的含義。

用孫悟空的例子來說,必須永遠(yuǎn)把孫悟空的所有變化都當(dāng)成孫悟空來對待,而如果把老孫變成的雀兒當(dāng)成雀兒,而不是老孫,那就被老孫騙了,而這是不應(yīng)當(dāng)發(fā)生的。

下面的做法是不對的:

 

大圣本尊 c = new 大圣本尊();
雀兒 bird 
= new 雀兒 (c);

 

半透明的裝飾模式

然而,純粹的裝飾模式很難找到。裝飾模式的用意是在不改變接口的前提下,增強所考慮的類的性能。在增強性能的時候,往往需要建立新的公開的方法。即 便是在孫大圣的系統(tǒng)里,也需要新的方法。比如齊天大圣類并沒有飛行的能力,而雀兒有。這就意味著雀兒應(yīng)當(dāng)有一個新的fly()方法。

這就導(dǎo)致了大多數(shù)的裝飾模式的實現(xiàn)都是"半透明"(semi-transparent)的,而不是完全"透明"的。換言之,允許裝飾模式改變接口, 增加新的方法。即聲明ConcreteDecorator類型的變量,從而可以調(diào)用ConcreteDecorator類中才有的方法:

 

齊天大圣 c = new 大圣本尊();
雀兒 bird 
= new 雀兒(c);
bird.fly();

 

齊天大圣接口根本沒有fly()這個方法,而雀兒接口里有這個方法。


九、 裝飾模式在.NET中的應(yīng)用

.net中存在如下類模型:

 

下面的代碼段用來將XmlDocument的內(nèi)容格式輸出。我們可以體會Decorator模式在這里所起的作用。

 

 

// 生成ConcreteComponent(內(nèi)存流ms)
MemoryStream ms = new MemoryStream();

// 用XmlTextWriter對內(nèi)存流 ms 進(jìn)行裝飾
// 此處使用了半透明的裝飾模式
XmlTextWriter xtw = new XmlTextWriter(ms, Encoding.UTF8);
xtw.Formatting 
= Formatting.Indented;

// 對裝飾xtw的操作會轉(zhuǎn)而操作本體-內(nèi)存流ms
xmlDoc.Save(xtw);

byte[] buf = ms.ToArray();
txtResult.Text 
= Encoding.UTF8.GetString(buf,0,buf.Length);
xtw.Close();

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多