不同的裝飾器模式(設計模式二)

前言

我是一名博客園的博主,目前排名第199675位,雖然排名稍稍落後,但這並不影響我向你們學習而後本身吹水。html

在常見的設計模式中,每一個項目或者說產品能夠說裝飾器幾乎必用。設計模式

裝飾器是decorator,別名wrapper,也稱爲包裝器,是建立型、結構型、行爲型分類的結構型,具體有什麼用呢?緩存

說有什麼用,不如直接看下,經過使用裝飾器有什麼結構變化,是如何演化過來的。網絡

經過演化過程,天然知道爲何裝飾器劃分爲結構型,裝飾器解決了什麼問題,做用是啥。app

上車出發

在流中,有文件流、內存流以及網絡流,他們的讀取方式都不同,可是它們都繼承steam 這個類。 像這樣:ide

public abstract class Stream
{
	protected abstract char Read(int number);

	protected abstract void seek(int position = 0);

	protected virtual void write(byte data) { }
}

假設讓咱們來分別設計文件流、內存流與網絡流 文件流:學習

public class FileStream: Stream
{

	public virtual void write(byte data) {
		// 寫入文件
	}

	public override char Read(int number)
	{
		throw new NotImplementedException();
	}

	public override void seek(int position = 0)
	{
		throw new NotImplementedException();
	}
}

內存流:this

public class MemoryStream:Stream
{

	public virtual void write(byte data)
	{
		// 寫內存流
	}

	public override char Read(int number)
	{
		throw new NotImplementedException();
	}

	public override void seek(int position = 0)
	{
		throw new NotImplementedException();
	}
}

網絡流:加密

public class NetworkStream: Stream
{

	public virtual void write(byte data)
	{
		// 寫網絡流
	}

	public override char Read(int number)
	{
		throw new NotImplementedException();
	}

	public override void seek(int position = 0)
	{
		throw new NotImplementedException();
	}
}

咱們在讀取或者寫入這些流的時候,可能會進行加密或者說緩存。 初版設計,假設咱們以繼承的方式實現。 加密的文件流:spa

public class CryptoBufferedFileStream: FileStream
{
	public override  char Read(int number)
	{
		base.Read(number);
		//額外的加密操做
		throw new NotImplementedException();
	}
	public override void seek(int position)
	{
		//額外的加密操做
		base.seek(position);
	}
	public override void write(byte data)
	{
		//額外的加密操做...
		base.write(data);
	}
}

加密的內存流:

public class CryptoMemoryStream : MemoryStream
{
	public override char Read(int number)
	{
		base.Read(number);
		//額外的加密操做
		throw new NotImplementedException();
	}
	public override void seek(int position)
	{
		//額外的加密操做
		base.seek(position);
	}
	public override void write(byte data)
	{
		//額外的加密操做...
		base.write(data);
	}
}

加密的網絡流

public class CryptoNetworkStream : NetWorkStream
{
	public override char Read(int number)
	{
		base.Read(number);
		//額外的加密操做
		throw new NotImplementedException();
	}
	public override void seek(int position)
	{
		//額外的加密操做
		base.seek(position);
	}
	public override void write(byte data)
	{
		//額外的加密操做...
		base.write(data);
	}
}

一樣咱們還要實現緩存流:

//文件流緩衝
public class BufferedFileStream: FileStream
{
	public override char Read(int number)
	{
		base.Read(number);
		//額外的緩衝操做
		throw new NotImplementedException();
	}
	public override void seek(int position)
	{
		//額外的緩衝操做
		base.seek(position);
	}
	public override void write(byte data)
	{
		//額外的緩衝操做...
		base.write(data);
	}
}
//內存流緩衝
public class BufferedMemoryStream : MemoryStream
{
	public override char Read(int number)
	{
		base.Read(number);
		//額外的緩衝操做
		throw new NotImplementedException();
	}
	public override void seek(int position)
	{
		//額外的緩衝操做
		base.seek(position);
	}
	public override void write(byte data)
	{
		//額外的緩衝操做...
		base.write(data);
	}
}
//網絡流緩衝
public class BufferedNetworkStream : NetWorkStream
{
	public override char Read(int number)
	{
		base.Read(number);
		//額外的緩衝操做
		throw new NotImplementedException();
	}
	public override void seek(int position)
	{
		//額外的緩衝操做
		base.seek(position);
	}
	public override void write(byte data)
	{
		//額外的緩衝操做...
		base.write(data);
	}
}

寫完以後,會發現幾個致命性問題:

1.沒有實現咱們要加密也要緩存,若是要寫下去那麼還須要3個類,感受沒有盡頭。

假設steam 有n 個繼承基礎類,如FileSteam,須要實現m個擴展功能,好比說加密緩衝等。 那麼計算是n(C(m,1),c(m,2)....,C(m,m)) 計算C(m,1),c(m,2)....,C(m,m)=2^m-1 答案是n(2^m-1) 很差意思,個人數學不是很好,若是有錯誤,望請指正。 2.不管加密仍是緩存都是操做byte,並且操做都是read、write與seek,感受有太多類似性代碼了。

根據這兩點咱們改一下。 加密流:

public class CryptoBufferedStream:Stream
{
	Stream stream;

	public CryptoBufferedStream(Stream stream)
	{
		this.stream = stream;
	}

	public override char Read(int number)
	{
		stream.Read(number);
		//額外的加密操做
		throw new NotImplementedException();
	}
	public override void seek(int position)
	{
		//額外的加密操做
		stream.seek(position);
	}
	public override void write(byte data)
	{
		//額外的加密操做...
		stream.write(data);
	}
}

緩衝流:

public class BufferedMemoryStream : Stream
{
	Stream stream;

	public BufferedMemoryStream(Stream stream) {
		this.stream = stream;
	}

	public override char Read(int number)
	{
		stream.Read(number);
		//額外的緩衝操做
		throw new NotImplementedException();
	}
	public override void seek(int position)
	{
		//額外的緩衝操做
		stream.seek(position);
	}
	public override void write(byte data)
	{
		//額外的緩衝操做...
		stream.write(data);
	}
}

這樣彷佛就看起來舒服不少了,這裏可能會有一個疑惑性的問題, 爲何還要繼承Stream? 裝飾器也叫包裝器,咱們使用CryptoBufferedStream把文件流包裝成了加密文件流,包裝完也是必須是流啊,打包完別忘了打標籤哦。

調用示例:

static void Main(string[] args)
{
	FileStream fileStream = new FileStream();
	BufferedMemoryStream bufferedMemoryStream = new BufferedMemoryStream(fileStream);
}

這樣就把fileStream給包裝成了bufferedMemoryStream,後面咱們使用的就是BufferedMemoryStream。 這樣咱們沒有失去fileSteam 是流的特性,並且還要另一個好處,既然仍是流,那麼咱們還能夠繼續包裝啊。

CryptoBufferedStream cryptoBufferedStream = new CryptoBufferedStream(bufferedMemoryStream);

這時候咱們即加密了,也緩衝了,實現了咱們原來沒有寫的3個類。 這裏發現一個問題,那就是stream這個屬性在CryptoBufferedStream 和 BufferedMemoryStream 都存在。 其實提取和不提取都沒有關係,可是對咱們寫代碼的人來講,每次都要去寫個能夠提取出來的字段,是至關不舒服的,並且還不開心。 終版: 將stream屬性提取出來,提取到DecoratorStream中。

public abstract class DecoratorStream: Stream
{
	protected Stream stream;
	public DecoratorStream(Stream stream){
		this.stream = stream;
	}
}

public class CryptoBufferedStream: DecoratorStream
{

	public CryptoBufferedStream(Stream stream):base(stream)
	{
	}

	public override char Read(int number)
	{
		stream.Read(number);
		//額外的加密操做
		throw new NotImplementedException();
	}
	public override  void seek(int position)
	{
		//額外的加密操做
		stream.seek(position);
	}
	public override void write(byte data)
	{
		//額外的加密操做...
		stream.write(data);
	}
}

public class BufferedMemoryStream : DecoratorStream
{

	public BufferedMemoryStream(Stream stream):base(stream) {

	}

	public override char Read(int number)
	{
		stream.Read(number);
		//額外的緩衝操做
		throw new NotImplementedException();
	}
	public override void seek(int position)
	{
		//額外的緩衝操做
		stream.seek(position);
	}
	public override void write(byte data)
	{
		//額外的緩衝操做...
		stream.write(data);
	}
}

看起來就舒服不少了。 爲何看起來會舒服,一張圖解釋出來。 假設steam 有n 個繼承基礎類,如FileSteam,須要實現m個擴展功能,好比說加密緩衝等。按照裝飾器的計算方式是:m+1 n(2^m-1)與m+1 二者的方式對比顯而易見啊,如今能夠證實爲何裝飾器是一個結構模式了吧。 至於做用,能夠看出,能夠解決繼承致使的子類膨脹問題。

uml圖

後面補上,畫圖累啊。

總結

由於n(2^m-1)在n>1或者m大於1的狀況下,n(2^m-1)=>m+1,且僅當m=2時候二者相等,因此做用爲:能夠解決繼承致使的子類膨脹問題,膨脹問題屬於結構問題,解決的是結構問題,因此歸屬爲結構型。

原文出處:https://www.cnblogs.com/aoximin/p/12078650.html

相關文章
相關標籤/搜索