设计模式(八):装饰模式
模式動機
一般有兩種方式可以實現(xiàn)給一個類或?qū)ο笤黾有袨?#xff1a;
- 繼承機制,使用繼承機制是給現(xiàn)有類添加功能的一種有效途徑,通過繼承一個現(xiàn)有類可以使得子類在擁有自身方法的同時還擁有父類的方法。但是這種方法是靜態(tài)的,用戶不能控制增加行為的方式和時機。
- 關(guān)聯(lián)機制,即將一個類的對象嵌入另一個對象中,由另一個對象來決定是否調(diào)用嵌入對象的行為以便擴展自己的行為,我們稱這個嵌入的對象為裝飾器(Decorator)
裝飾模式以對客戶透明的方式動態(tài)地給一個對象附加上更多的責任,換言之,客戶端并不會覺得對象在裝飾前和裝飾后有什么不同。裝飾模式可以在不需要創(chuàng)造更多子類的情況下,將對象的功能加以擴展。這就是裝飾模式的模式動機。
模式定義
裝飾模式(Decorator Pattern) :動態(tài)地給一個對象增加一些額外的職責(Responsibility),就增加對象功能來說,裝飾模式比生成子類實現(xiàn)更為靈活。其別名也可以稱為包裝器(Wrapper),與適配器模式的別名相同,但它們適用于不同的場合。根據(jù)翻譯的不同,裝飾模式也有人稱之為“油漆工模式”,它是一種對象結(jié)構(gòu)型模式。
模式結(jié)構(gòu)
裝飾模式包含如下角色:
- Component: 抽象構(gòu)件
- ConcreteComponent: 具體構(gòu)件
- Decorator: 抽象裝飾類
- ConcreteDecorator: 具體裝飾類
代碼示例
這里我們的用例場景是,在讀取的時候,我們需要在這之前增加一些業(yè)務邏輯:
讀取的接口:
package cn.edu.hust.decorator;public interface InputStream {void read(byte[] bytes); }一般的文件讀取類,這個類只是簡單的讀取一下:
package cn.edu.hust.decorator;public class FileInputStream implements InputStream {//簡單的讀取字節(jié)public void read(byte[] bytes) {System.out.println(new String(bytes));} }假設我們需要在讀取之前增加一些業(yè)務邏輯,我們使用一個裝飾器類來實現(xiàn)
package cn.edu.hust.decorator;public class StringInputStream implements InputStream {private InputStream inputStream;public StringInputStream(InputStream inputStream) {this.inputStream = inputStream;}public void read(byte[] bytes) {inputStream.read(bytes);} }具體的裝飾器類
package cn.edu.hust.decorator;public class StringBufferInputStream extends StringInputStream {private InputStream inputStream;public StringBufferInputStream(InputStream inputStream) {super(inputStream);}//這里在讀取字符串之前輸入一些內(nèi)容@Overridepublic void read(byte[] bytes) {System.out.println("這里是增強的方法。。。");super.read(bytes);} }客戶端的使用:
package cn.edu.hust.decorator;public class Client {public static void main(String[] args){InputStream inputStream=new FileInputStream();StringBufferInputStream stringBufferInputStream=new StringBufferInputStream(inputStream);stringBufferInputStream.read("這是一個文件".getBytes());} }模式分析
- 與繼承關(guān)系相比,關(guān)聯(lián)關(guān)系的主要優(yōu)勢在于不會破壞類的封裝性,而且繼承是一種耦合度較大的靜態(tài)關(guān)系,無法在程序運行時動態(tài)擴展。在軟件開發(fā)階段,關(guān)聯(lián)關(guān)系雖然不會比繼承關(guān)系減少編碼量,但是到了軟件維護階段,由于關(guān)聯(lián)關(guān)系使系統(tǒng)具有較好的松耦合性,因此使得系統(tǒng)更加容易維護。當然,關(guān)聯(lián)關(guān)系的缺點是比繼承關(guān)系要創(chuàng)建更多的對象。
- 使用裝飾模式來實現(xiàn)擴展比繼承更加靈活,它以對客戶透明的方式動態(tài)地給一個對象附加更多的責任。裝飾模式可以在不需要創(chuàng)造更多子類的情況下,將對象的功能加以擴展。
模式優(yōu)點
裝飾模式的優(yōu)點:
- 裝飾模式與繼承關(guān)系的目的都是要擴展對象的功能,但是裝飾模式可以提供比繼承更多的靈活性。
- 可以通過一種動態(tài)的方式來擴展一個對象的功能,通過配置文件可以在運行時選擇不同的裝飾器,從而實現(xiàn)不同的行為。
- 通過使用不同的具體裝飾類以及這些裝飾類的排列組合,可以創(chuàng)造出很多不同行為的組合。可以使用多個具體裝飾類來裝飾同一對象,得到功能更為強大的對象。
- 具體構(gòu)件類與具體裝飾類可以獨立變化,用戶可以根據(jù)需要增加新的具體構(gòu)件類和具體裝飾類,在使用時再對其進行組合,原有代碼無須改變,符合“開閉原則”
模式缺點
裝飾模式的缺點:
- 使用裝飾模式進行系統(tǒng)設計時將產(chǎn)生很多小對象,這些對象的區(qū)別在于它們之間相互連接的方式有所不同,而不是它們的類或者屬性值有所不同,同時還將產(chǎn)生很多具體裝飾類。這些裝飾類和小對象的產(chǎn)生將增加系統(tǒng)的復雜度,加大學習與理解的難度。
- 這種比繼承更加靈活機動的特性,也同時意味著裝飾模式比繼承更加易于出錯,排錯也很困難,對于多次裝飾的對象,調(diào)試時尋找錯誤可能需要逐級排查,較為煩瑣。
適用環(huán)境
在以下情況下可以使用裝飾模式:
- 在不影響其他對象的情況下,以動態(tài)、透明的方式給單個對象添加職責。
- 需要動態(tài)地給一個對象增加功能,這些功能也可以動態(tài)地被撤銷。
- 當不能采用繼承的方式對系統(tǒng)進行擴充或者采用繼承不利于系統(tǒng)擴展和維護時。不能采用繼承的情況主要有兩類:第一類是系統(tǒng)中存在大量獨立的擴展,為支持每一種組合將產(chǎn)生大量的子類,使得子類數(shù)目呈爆炸性增長;第二類是因為類定義不能繼承(如final類).
原文鏈接:https://github.com/oeljeklaus-you/Design-Patterns/blob/master/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F(%E5%85%AB)%E8%A3%85%E9%A5%B0%E6%A8%A1%E5%BC%8F.md
總結(jié)
以上是生活随笔為你收集整理的设计模式(八):装饰模式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Windows server 2012镜
- 下一篇: 实验室管理软件 费用报销 项目经费 试剂