【設計模式】裝飾(器)模式 透明裝飾模式與半透明裝飾模式

裝飾模式(Decorator Pattern)詳解


一、裝飾模式簡介

裝飾模式(Decorator Pattern) 是一種 結構型設計模式,它允許你動態地給對象添加行為或職責,而無需修改其源代碼,也不需要使用繼承來擴展功能。

是一種用于替代繼承的技術,它通過一種無須定義子類的方式給對象動態增加職責,使用對象之間的關聯關系取代類之間的繼承關系

引入了裝飾類,在裝飾類中既可以調用待裝飾的原有類的方法,還可以增加新的方法,以擴展原有類的功能

你可以把它理解為“在不改變原對象的前提下,為其添加新功能的方式”。與繼承不同的是,裝飾模式是運行時動態組合的,更加靈活。

動態地給一個對象增加一些額外的職責。就擴展功能而言,裝飾模式提供了一種比使用子類更加靈活的替代方案

以對客戶透明的方式動態地給一個對象附加上更多的責任
可以在不需要創建更多子類的情況下,讓對象的功能得以擴展

裝飾模式的結構

裝飾模式包含以下4個角色:

Component(抽象構件)
ConcreteComponent(具體構件)
Decorator(抽象裝飾類)
ConcreteDecorator(具體裝飾類)

在這里插入圖片描述


二、解決的問題類型

裝飾模式主要用于解決以下問題:

  • 當子類擴展不再適用:比如當你有多個可選功能,并且這些功能可以自由組合時,如果用繼承方式實現,會導致類爆炸。
  • 希望以透明和動態的方式給對象添加職責:不需要修改客戶端代碼,就可以為對象添加新的功能。
  • 保持類責任清晰:每個裝飾器只關注一個功能,符合單一職責原則。

三、使用場景

  1. 你想在不影響其他對象的情況下,動態、透明地給某個對象添加職責。
  2. 你需要在運行時決定是否添加某個功能,甚至多次添加多個功能。
  3. 替代多重繼承的方案:避免由于多層繼承導致的類爆炸問題。
  4. Java I/O 流系統中廣泛使用裝飾者模式,如 BufferedInputStream 包裹 FileInputStream
  5. 不能采用繼承的方式對系統進行擴展或者采用繼承不利于系統擴展和維護時可以使用裝飾模式

四、實際生活案例

想象你在點一杯咖啡:

  • 基礎咖啡:美式咖啡(Espresso)
  • 可選配料:牛奶(Milk)、摩卡(Mocha)、奶油(Whip)

每種配料都可以看作是對咖啡的“裝飾”,你可以選擇加一樣,也可以疊加多種,最終價格也會隨之變化。

這種“基礎 + 動態添加”的場景非常適合使用裝飾模式。


五、代碼案例

我們通過一個簡單的咖啡加料的例子來演示裝飾模式。

1. 定義組件接口

// 組件接口:飲料
interface Beverage {double cost();     // 價格String description(); // 描述
}

2. 實現具體組件(基礎對象)

// 具體組件:美式咖啡
class Espresso implements Beverage {@Overridepublic double cost() {return 2.0;}@Overridepublic String description() {return "Espresso";}
}

3. 抽象裝飾器類(所有裝飾器的基礎)

// 抽象裝飾器類
abstract class BeverageDecorator implements Beverage {protected Beverage decoratedBeverage;public BeverageDecorator(Beverage decoratedBeverage) {this.decoratedBeverage = decoratedBeverage;}@Overridepublic double cost() {return decoratedBeverage.cost();}@Overridepublic String description() {return decoratedBeverage.description();}
}

4. 具體裝飾器類(裝飾行為)

// 加牛奶的裝飾器
class MilkDecorator extends BeverageDecorator {public MilkDecorator(Beverage decoratedBeverage) {super(decoratedBeverage);}@Overridepublic double cost() {return super.cost() + 0.5;}@Overridepublic String description() {return super.description() + ", Milk";}
}// 加摩卡的裝飾器
class MochaDecorator extends BeverageDecorator {public MochaDecorator(Beverage decoratedBeverage) {super(decoratedBeverage);}@Overridepublic double cost() {return super.cost() + 0.7;}@Overridepublic String description() {return super.description() + ", Mocha";}
}// 加奶油的裝飾器
class WhipDecorator extends BeverageDecorator {public WhipDecorator(Beverage decoratedBeverage) {super(decoratedBeverage);}@Overridepublic double cost() {return super.cost() + 0.6;}@Overridepublic String description() {return super.description() + ", Whip";}
}

5. 客戶端調用示例

public class Client {public static void main(String[] args) {// 點一杯加牛奶和摩卡的咖啡Beverage beverage = new Espresso();beverage = new MilkDecorator(beverage);beverage = new MochaDecorator(beverage);System.out.println("Cost: $" + beverage.cost());System.out.println("Description: " + beverage.description());// 再加奶油beverage = new WhipDecorator(beverage);System.out.println("\nAfter adding whip:");System.out.println("Cost: $" + beverage.cost());System.out.println("Description: " + beverage.description());}
}

輸出結果:

Cost: $3.2
Description: Espresso, Milk, MochaAfter adding whip:
Cost: $3.8
Description: Espresso, Milk, Mocha, Whip
抽象構件類典型代碼(c++)
abstract class Component
{public abstract void Operation();
}
具體構件類典型代碼
class ConcreteComponent : Component
{public override void Operation(){//基本功能實現}
}
抽象裝飾類典型代碼
class Decorator : Component
{
private Component component;  //維持一個對抽象構件對象的引用//注入一個抽象構件類型的對象public Decorator(Component component){this.component = component;}public override void Operation(){component.Operation();  //調用原有業務方法}
}
具體裝飾類典型代碼
class ConcreteDecorator : Decorator
{public ConcreteDecorator(Component component) : base(component){}public override void Operation() {base.Operation();  //調用原有業務方法AddedBehavior();  //調用新增業務方法}
//新增業務方法    
public void AddedBehavior() {	//功能擴展}
}
其他案例
  1. 某軟件公司基于面向對象技術開發了一套圖形界面構件庫——VisualComponent,該構件庫提供了大量基本構件,如窗體、文本框、列表框等,由于在使用該構件庫時,用戶經常要求定制一些特殊的顯示效果,如帶滾動條的窗體、帶黑色邊框的文本框、既帶滾動條又帶黑色邊框的列表框等等,因此經常需要對該構件庫進行擴展以增強其功能。
    現使用裝飾模式來設計該圖形界面構件庫。
    在這里插入圖片描述
  2. 變形金剛:變形金剛在變形之前是一輛汽車,它可以在陸地上移動。當它變成機器人之后除了能夠在陸地上移動之外,還可以說話;如果需要,它還可以變成飛機,除了在陸地上移動還可以在天空中飛翔。
    在這里插入圖片描述
  3. 多重加密系統:
    某系統提供了一個數據加密功能,可以對字符串進行加密。最簡單的加密算法通過對字母進行移位來實現,同時還提供了稍復雜的逆向輸出加密,還提供了更為高級的求模加密。用戶先使用最簡單的加密算法對字符串進行加密,如果覺得還不夠可以對加密之后的結果使用其他加密算法進行二次加密,當然也可以進行第三次加密。現使用裝飾模式設計該多重加密系統

在這里插入圖片描述


六、優缺點分析

優點描述
? 比繼承更靈活可在運行時動態添加功能,避免了類爆炸問題。可以通過一種動態的方式來擴展一個對象的功能,通過配置文件可以在運行時選擇不同的具體裝飾類,從而實現不同的行為
? 遵循開閉原則擴展功能時不需要修改原有代碼。具體構件類與具體裝飾類可以獨立變化,用戶可以根據需要增加新的具體構件類和具體裝飾類,且原有類庫代碼無須改變,符合開閉原則
? 職責分離清晰每個裝飾器只負責一個功能,便于維護和復用。可以對一個對象進行多次裝飾
缺點描述
? 增加系統復雜度多個裝飾器嵌套后可能讓代碼難以理解和調試。使用裝飾模式進行系統設計時將產生很多小對象,大量小對象的產生勢必會占用更多的系統資源,在一定程度上影響程序的性能
? 調試困難對象層層包裝,追蹤執行路徑較為麻煩。比繼承更加易于出錯,排錯也更困難,對于多次裝飾的對象,調試時尋找錯誤可能需要逐級排查,較為煩瑣
? 容易誤用裝飾順序某些情況下裝飾順序會影響最終效果,需特別注意。

七、與其他模式對比(補充)

模式名稱目標
代理模式控制對對象的訪問,強調保護或增強,但不改變接口。
適配器模式解決接口不兼容問題,強調轉換。
裝飾模式動態增強對象功能,強調組合和擴展。

八、最終小結

裝飾模式是一種非常實用的設計模式,尤其適合用于那些需要在不修改現有對象的前提下動態擴展其功能的場景。

它的核心思想是:

組合優于繼承”,“透明地增強對象能力”。

在 Java 中,最經典的使用就是 IO 流體系,例如 BufferedReader(new InputStreamReader(System.in)),就是一個典型的裝飾鏈。

作為一名 Java 開發工程師,掌握裝飾模式可以幫助你寫出更優雅、更靈活、更容易擴展的代碼,特別是在開發插件化、模塊化系統時尤為重要。

如果你正在設計一個需要支持“插件式”功能擴展的系統,或者希望避免因繼承帶來的類爆炸問題,那么裝飾模式將是一個非常好的選擇。


📌 一句話總結:

裝飾模式就像“洋蔥”,一層層包裹原始對象,在不破壞原有結構的前提下,動態賦予新功能。

九、擴展

透明裝飾模式

透明(Transparent)裝飾模式:要求客戶端完全針對抽象編程,裝飾模式的透明性要求客戶端程序不應該將對象聲明為具體構件類型或具體裝飾類型,而應該全部聲明為抽象構件類型。

對于客戶端而言,具體構件對象和具體裝飾對象沒有任何區別。

可以讓客戶端透明地使用裝飾之前的對象和裝飾之后的對象,無須關心它們的區別
可以對一個已裝飾過的對象進行多次裝飾,得到更為復雜、功能更為強大的對象
無法在客戶端單獨調用新增方法AddedBehavior()

……
Component component_o,component_d1,component_d2; //全部使用抽象構件定義
component_o = new ConcreteComponent();
component_d1 = new ConcreteDecorator1(component_o);
component_d2 = new ConcreteDecorator2(component_d1);
component_d2.Operation();
//無法單獨調用component_d2的AddedBehavior()方法
……

半透明裝飾模式

半透明(Semi-transparent)裝飾模式:用具體裝飾類型來定義裝飾之后的對象,而具體構件使用抽象構件類型來定義。
對于客戶端而言,具體構件類型無須關心,是透明的;但是具體裝飾類型必須指定,這是不透明的。

可以給系統帶來更多的靈活性,設計相對簡單,使用起來也非常方便
客戶端使用具體裝飾類型來定義裝飾后的對象,因此可以單獨調用AddedBehavior()方法
最大的缺點在于不能實現對同一個對象的多次裝飾,而且客戶端需要有區別地對待裝飾之前的對象和裝飾之后的對象

……
Component component_o; //使用抽象構件類型定義
component_o = new ConcreteComponent();
component_o.Operation();
ConcreteDecorator component_d; //使用具體裝飾類型定義
component_d = new ConcreteDecorator(component_o);
component_d.Operation();
component_d.AddedBehavior(); //單獨調用新增業務方法
……

以上內容部分由AI大模型生成,注意識別!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/914697.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/914697.shtml
英文地址,請注明出處:http://en.pswp.cn/news/914697.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

NAT原理與實驗指南:網絡地址轉換技術解析與實踐

NAT實驗 NAT(Network Address Translation,網絡地址轉換): NAT技術的介紹: 隨著Internet用戶的快速增長,以及地址分配不均等因素,IPv4地址(約40億的空間地址)已經陷入不…

設計模式之【觀察者模式】

目錄 觀察者模式中的角色 通過一個簡單案例來演示觀察者模式 被觀察者接口 事件類型 up主類作為被觀察者 觀察者接口 粉絲類作為觀察者 測試 測試結果 觀察者模式中的角色 被觀察者(observable)觀察者(observer) 通過一個簡單案例來演示觀察者模式 被觀察者接口 /*…

Linux sudo host權限提升漏洞(CVE-2025-32462)復現與原理分析

免責聲明 本文所述漏洞復現方法僅供安全研究及授權測試使用; 任何個人/組織須在合法合規前提下實施,嚴禁用于非法目的; 作者不對任何濫用行為及后果負責,如發現新漏洞請及時聯系廠商并遵循漏洞披露規則。 漏洞簡述 Linux sudo是l…

【uni-ui】hbuilderx的uniapp 配置 -小程序左滑出現刪除等功能

1.網址:https://ext.dcloud.net.cn/plugin?id181](https://ext.dcloud.net.cn/plugin?id181) 2.csdn講解:https://blog.csdn.net/qq_40323256/article/details/114337128 3.uni-ui git:https://github.com/dcloudio/uni-ui 4.官方網址文檔&…

記一次POST請求中URL中文參數亂碼問題的解決方案

POST請求中URL中文參數亂碼前言:一個常見的開發痛點一、問題現象與原因深度解析1. 典型問題場景2. 根本原因分析URL編碼規范問題:編碼解碼過程不一致:IE瀏覽器特殊行為:二、前端解決方案1. 手動編碼URL參數(推薦&#…

從存儲熱遷移流程了解 QEMU block layer

文章目錄存儲熱遷移流程總體流程代碼路徑QEMU Block layer架構簡述Block Job結構體設計狀態轉換Mirror block job拓撲結構構建過程數據結構存儲熱遷移流程 總體流程 Libvirt migrate 命令提供 copy-storage-all 選項支持存儲熱遷移,相應地,Libvirt 熱遷…

【設計模式】命令模式 (動作(Action)模式或事務(Transaction)模式)宏命令

命令模式(Command Pattern)詳解一、命令模式簡介 命令模式(Command Pattern) 是一種 行為型設計模式(對象行為型模式),它將一個請求封裝為一個對象,從而使你可以用不同的請求對客戶進…

HTML5智能排班日歷:動態排班一目了然

這個日歷將具備以下功能: 顯示一個標準的月度日歷視圖。可以自由切換上一個月和下一個月。在日歷的每一天自動顯示當天值班的人員。您可以很方便地在文件中修改值班人員列表和排班的起始日期。包括:動態生成日歷網格處理月份切換根據排班規則計算并顯示每天的值班人員<!DO…

深度剖析C++生態系統:一門老牌語言如何在開源浪潮中煥發新生?

&#x1f4dd;個人主頁&#x1f339;&#xff1a;慌ZHANG-CSDN博客 &#x1f339;&#x1f339;期待您的關注 &#x1f339;&#x1f339; 一、前言&#xff1a;C的“長壽秘訣”是什么&#xff1f; C 誕生已超過 40 年。它經歷了桌面應用、互聯網爆發、移動時代&#xff0c;再…

60個功能OfficeBox 萬彩辦公大師:PDF 格式轉換 OCR識別免費無廣告

各位辦公小能手們&#xff01;今天給大家介紹個超厲害的免費辦公工具套裝——OfficeBox萬彩辦公大師&#xff0c;是廣州萬彩科技整出來的。軟件下載地址安裝包 它里面有60多個沒廣告的綠色組件&#xff0c;簡直像個百寶箱&#xff01;涵蓋了PDF處理、格式轉換、OCR識別、屏幕錄…

擁抱主權AI:OpenCSG驅動智能體運營,共筑新加坡智能高地

2025年7月11日&#xff0c;由Linux基金會AI & Data、TikTok及LF Edge聯合主辦的 【LF AI & Data Day Singapore 2025】 在新加坡TikTok總部盛大啟幕。本次大會以“Agent for SWE”為核心議題&#xff0c;匯聚全球頂尖AI開發者、企業領袖及開源社區先鋒。作為國家主權AI…

單片機學習筆記.根據芯片數據手冊寫驅動程序(這里使用的是普中開發版,以DS1302為例)

硬件原理圖部分&#xff1a; VCC2:是主電源 VCC1&#xff1a;是備用電源&#xff0c;此處沒有使用VCC1 查芯片數據手冊的網站&#xff1a; ALLDATASHEETCN.COM - 電子元件和半導體及其他半導體的數據表搜索網站。https://www.alldatasheetcn.com/ 1.由原理圖可知對應引腳&…

Capture One24下載與保姆級安裝教程!

軟件下載 軟件名稱&#xff1a;Capture One24 軟件語言&#xff1a;簡體中文 軟件大小&#xff1a;1.06G 系統要求&#xff1a;Windows7或更高&#xff0c;32/64位操作系統 硬件要求&#xff1a;CPU2.5GHz&#xff0c;RAM4G或更高 下載通道丨下載&#xff1a;https://too…

微信小程序(數據庫)

const dbwx.cloud.database()//連接數據庫db.collection("test").doc("b69f67c0626fac9000e123fc1ff07a42&#xff08;為要查詢數據的id&#xff09;").get({success:res>{console.log(res)}})或getData(){db.collection("test").doc("&…

Apache CXF 漏洞曝光:存在拒絕服務與數據泄露雙重風險

Apache軟件基金會近日披露了一個影響多個Apache CXF版本的安全漏洞&#xff08;CVE-2025-48795&#xff09;。Apache CXF是開發者廣泛使用的開源Web服務框架&#xff0c;用于構建基于SOAP和REST的應用程序。漏洞雙重威脅該漏洞具有雙重危害性&#xff1a;一方面可能通過內存耗盡…

Android 應用自動更新:從理論到實戰的硬核指南

目錄 1. 自動更新的核心邏輯:為什么它對用戶體驗至關重要? 自動更新的本質 為什么它如此重要? 2. 版本檢測:如何優雅地發現“新大陸”? 設計版本檢測的邏輯 實現版本檢測的 API 請求 用戶體驗優化 3. 下載新版本:穩妥地獲取安裝包 下載的兩種方式 注意事項 用戶…

每日面試題05:ArrayList和LinkedList的底層原理

ArrayList與LinkedList深度解析&#xff1a;從底層原理到實戰選擇在Java的List接口實現中&#xff0c;ArrayList和LinkedList是最常用的兩種選擇。面試中“它們的區別”幾乎是必問題&#xff0c;但僅僅停留在“數組vs鏈表”的層面顯然不夠。本文將從??底層數據結構、內存布局…

python的慈善捐贈平臺管理信息系統

前端開發框架:vue.js 數據庫 mysql 版本不限 后端語言框架支持&#xff1a; 1 java(SSM/springboot)-idea/eclipse 2.NodejsVue.js -vscode 3.python(flask/django)–pycharm/vscode 4.php(thinkphp/laravel)-hbuilderx 數據庫工具&#xff1a;Navicat/SQLyog等都可以 摘要 本文…

三十二、【核心功能改造】數據驅動:重構儀表盤與關鍵指標可視化

三十二、【核心功能改造】數據驅動:重構儀表盤與關鍵指標可視化 前言準備工作第一部分:后端實現 - 統計 API1. 創建 `DashboardStatsView`2. 注冊統計 API 路由3. 后端初步測試第二部分:前端實現 - 重構儀表盤頁面1. 創建 `api/dashboard.ts` API 服務2. 重構 `HomeView.vue…

神經網絡與深度學習Python入門

一、神經網絡基礎 1. 神經元模型 在神經網絡中&#xff0c;最基本的單元是神經元&#xff08;Neuron&#xff09;&#xff0c;也稱為節點或單元。它模擬了生物神經系統中的神經元行為。一個典型的神經元模型包含多個輸入&#xff08;x1,x2,…,xnx_1, x_2, \ldots, x_nx1?,x2?…