設計模式之裝飾模式

定義

裝飾模式(Decorator Pattern),動態(組合)地給一個物件新增(擴充套件)一些額外的職責,就增加功能來說,裝飾模式比生成子類更為靈活。

結構圖

設計模式之裝飾模式

裝飾模式結構圖

參與者

Component:定義一個物件介面,可以給這些物件動態地新增職責。ConcreteComponent:定義一個物件,可以給這個物件新增一些職責。 Decorator:維持一個指向Component的指標,並定義一個與Component介面一致的介面。 ConcreteDecorator:負責向ConcreteComponent新增功能。 在裝飾模式中,Decorator定義了一個裝飾介面類。因為Decorator與ConcreteComponent繼承同一個介面,所以繼承Decorator的類ConcreteDecorator可以使用ConcreteComponent的方法,再在ConcreteDecorator裡面加入一些新的方法,也就是裝飾,就成為了一個包裝好的裝飾類。

程式碼示例

下面我們用。net中“Stream-流”的設計來說明此模式,具體程式碼如下:

//流-抽象類

public abstract class Stream

{

//設定當前流中的位置

public abstract long Seek(long offset, System。IO。SeekOrigin origin);

//從當前流讀取位元組序列

public abstract int Read(byte[] buffer, int offset, int count);

//向當前流中寫入位元組序列

public abstract void Write(byte[] buffer, int offset, int count);

}

//檔案流

public class FileStream : Stream

{

public override long Seek(long offset, System。IO。SeekOrigin origin)

{

//檔案流具體實現

return 0;

}

public override int Read(byte[] buffer, int offset, int count)

{

//檔案流具體實現

return 0;

}

public override void Write(byte[] buffer, int offset, int count)

{

//檔案流具體實現

}

}

//網路流

public class NetworkStream : Stream

{

public override long Seek(long offset, System。IO。SeekOrigin origin)

{

//網路流具體實現

return 0;

}

public override int Read(byte[] buffer, int offset, int count)

{

//網路流具體實現

return 0;

}

public override void Write(byte[] buffer, int offset, int count)

{

//網路流具體實現

}

}

//繼承Stream,遵循規範

public abstract class DecoratorStream : Stream

{

//組合(維持一個指向Stream的指標)

protected Stream strm;

public DecoratorStream(Stream strm)

{

this。strm = strm;

}

}

//加密流,擴充套件操作

public class CryptoStream : DecoratorStream

{

public CryptoStream(Stream strm) : base(strm)

{

}

public override long Seek(long offset, System。IO。SeekOrigin origin)

{

//。。。。具體加密操作(加密就是AddedBehavior,擴充套件了檔案流,網路流等;動態決定)

strm。Seek(offset, origin);//主體操作

return 0;

}

public override int Read(byte[] buffer, int offset, int count)

{

//。。。。具體加密操作

strm。Read(buffer, offset, count);

return 0;

}

public override void Write(byte[] buffer, int offset, int count)

{

//。。。。具體加密操作

strm。Write(buffer, offset, count);

}

}

//快取流,擴充套件操作

public class BufferedStream : DecoratorStream

{

public BufferedStream(Stream strm) : base(strm)

{

}

public override long Seek(long offset, System。IO。SeekOrigin origin)

{

//。。。。具體快取操作(快取就是AddedBehavior,擴充套件了檔案流,網路流等;動態決定)

strm。Seek(offset, origin);//主體操作

return 0;

}

public override int Read(byte[] buffer, int offset, int count)

{

//。。。。具體快取操作

strm。Read(buffer, offset, count);

return 0;

}

public override void Write(byte[] buffer, int offset, int count)

{

//。。。。具體快取操作

strm。Write(buffer, offset, count);

}

}

public class Client

{

public static void Main()

{

//加密檔案流(執行時裝配)

Stream s1 = new CryptoStream(new FileStream());

//快取網路流

Stream s2 = new BufferedStream(new NetworkStream());

//加密快取網路流

Stream buffer = new CryptoStream(new BufferedStream(new NetworkStream()));

}

}

總結

裝飾模式的特點:

比靜態類更靈活。使用裝飾模式可以很容易地向物件新增職責的方式。可以用新增和分離的方法,對裝飾在執行時新增和刪除職責。相比之下,繼承機制要求為每個新增的職責建立一個新的子類。這會產生很多新的類,並會增加系統的複雜度。

使用裝飾模式可以很容易地重複新增一個特性,而兩次繼承特性類則極容易出錯。

為了避免處理頂層的類有太多的特徵。裝飾模式下,你可以定義一個簡單的類,並用裝飾類給它逐漸地新增功能。這樣可以從簡單的部件組合出複雜的功能,具有低依賴性和地複雜性。