C 設計模式《六》 Decorator裝飾模式

2021-07-15 04:33:58 字數 4670 閱讀 9574

在軟體元件的設計中,如果責任劃分的不清晰,使用繼承得到的結果往往是隨需求的變化,子類急劇膨脹,同時充斥著重複**,這時候的關鍵是劃清責任。

典型模式

- decorator

- bridge

在某些情況下我們可能會「過度地使用繼承來擴充套件物件的功能」,由於繼承為型別引入的靜態特質,使得這種擴充套件方式缺乏靈活性;並且隨著子類的增多(擴充套件功能的增多),各種子類的組合(擴充套件)會導致更多子類的膨脹

那麼如何使「物件功能的擴充套件」能夠根據需要動態的實現?同時避免「擴充套件功能的增多」帶來的子類膨脹問題?從而使得任何「功能擴充套件變化」所導致的影響將為最低。

問題描述:設計一組與流相關的類,首先定義乙個抽象基類stream,之後繼承各種,如filestream,networkstream,memorystream。之後對流進行擴充套件操作,如加密操作,拷貝操作等。

//業務操作

class stream

};//主體類,檔案流

class filestream: public stream

virtual void seek(int position)

virtual void write(char data)

};//網路流

class networkstream :public stream

virtual void seek(int position)

virtual void write(char data)

};//記憶體流

class memorystream :public stream

virtual void seek(int position)

virtual void write(char data)

};//擴充套件操作,加密檔案流

class cryptofilestream :public filestream

virtual void seek(int position)

virtual void write(byte data)

};//擴充套件操作,加密網路流

class cryptonetworkstream : public networkstream

virtual void seek(int position)

virtual void write(byte data)

};//擴充套件操作,加密記憶體流

class cryptomemorystream : public memorystream

virtual void seek(int position)

virtual void write(byte data)

};//擴充套件的操作,快取檔案流

class bufferedfilestream : public filestream;

//擴充套件的操作,快取網路流

class bufferednetworkstream : public networkstream;

//擴充套件的操作,快取記憶體流

class bufferedmemorystream : public memorystream

//擴充套件的操作,加密緩衝檔案流

class cryptobufferedfilestream :public filestream

virtual void seek(int position)

virtual void write(byte data)

};void process()

分析:

以上例子是關於:對各種流的操作的,開始只有三個要求(檔案流filestream,網路流networkstream,記憶體流memorystream),然後這三個類都繼承於乙個抽象類(stream);之後提出各種需求,需要進行加密操作,快取操作等等。因此就有了各種擴充套件情況。下圖可以看出其關係。

什麼問題呢?可以看出以上的**存在大量的**冗餘(比如:加密操作都是一樣的,無論是針對檔案流還是網路流,加密檔案流cryptofilestream的讀操作和加密網路流的都操作都是先加密再讀),也就是一樣的**。再看看對cryptofilestream,cryptonetworkstream,cryptomemorystream進行一部分更改(將繼承改為組合)的**(只看讀操作)

class cryptofilestream :

};class cryptonetworkstream

};class cryptomemorystream

};

上面的**是不是很像,其中各個類新增的成員(filestream stream,networkstream stream,memorystream* stream)是不是可以進一步更改為stream* stream就可以了。更改完的**如下

class cryptofilestream :

};class cryptonetworkstream

};class cryptomemorystream

};

編譯時一樣,執行時不一樣絕大多數設計模式的原理,執行時讓他變化(用多型來支援其變化)。

這樣做完後,你發現這三個類是不是一模一樣,那只需要乙個類就行了(妙!!!)。這樣就消除了重複性,優化的**如下

class cryptofilestream :

};

上面**,但你有沒有發現乙個問題,cryptofilestream裡的read憑什麼是虛函式,因此必須得繼承基類(是為了完善介面規範),因此修改如下

class cryptostream: public stream 

virtual char read(int number)

virtual void seek(int position)

virtual void write(byte data)

};

這樣cryptofilestream既有個基類的字段,也繼承基類;同樣buffer操作的**優化同上訴方法一樣。

這樣改完後 ,就可以這樣使用

void process()
執行時裝配什麼意思呢?編譯時不存在快取檔案流,什麼加密檔案流等等,沒有那樣的類,執行時可以通過組合裝配起來滿足需求。這就是裝飾的含義,裝飾是附著在其他物件上圖示如下

以上做法已經很完善了。但是,如果某乙個類的子類有同樣的字段時,應該往上提。提到哪?

方法一:提到基類。但是filestream不需要這個字段。提到基類不合適。

因此需要設計中間類,見下的第三個版本

//業務操作

class stream

};//主體類

class filestream: public stream

virtual

void seek(int position)

virtual

void write(char data)

};class networkstream :public stream

virtual

void seek(int position)

virtual

void write(char data)

};class memorystream :public stream

virtual

void seek(int position)

virtual

void write(char data)

};//擴充套件操作,中間類

decoratorstream: public stream

};class cryptostream: public decoratorstream

virtual

char read(int number)

virtual

void seek(int position)

virtual

void write(byte data)

};class bufferedstream : public decoratorstream

//...

};

當然,物件導向設計原則 裡就有條」用組合代替繼承」

動態(組合)地給乙個物件增加乙個額外的職責。就增加功能而言。decorator模式比生成子類(繼承)更為靈活(消除重複**&減少子類個數)

結構圖如下

C 模式設計 Decorator 裝飾模式

需要設計圓 矩形兩種形狀,同時設計這兩種形狀的紅色 藍色版本,按照傳統的思路,使用繼承的方式,則如下圖 按這種方式,當需要的形狀和顏色種類增多時,所定義的類的數量將會急劇增多,而且類之間會有很多重複的 如果運用裝飾模式的思想,依照 組合優先於繼承 原則,將 顏色 單獨定義為乙個 裝飾類 該類也繼承自...

Decorator設計模式

雖然設計模式分得太細會有過度的趨勢,decorator某種程度上也是一種facade模式。但是實現起來還是比較漂亮的。而後面那個人的class arlist list,ilist的方法就不是decorator。它沒有乙個內部的list。這樣 however,now all of list s met...

設計模式 decorator模式

裝飾者模式體現了 敏捷開發思想中的 對類要 開放擴充套件,關閉修改.例子 乙個person主類 若干裝飾品類 紅衣服,藍衣服,藍鞋子,紅鞋子 測試 new乙個person 給他穿上紅衣服藍鞋子 code person介面 public inte ce ipersonperson類 package c...