設計模式 15 Decorator Pattern 裝飾器模式

設計模式 15?Decorator Pattern 裝飾器模式
1.定義

Decorator Pattern 裝飾器模式是一種結構型設計模式,它允許在運行時給對象添加新的行為或職責,而無需修改對象的源代碼。這種模式通過創建一個包裝對象,也稱為裝飾器,來包裹原始對象,裝飾器對象與原始對象有相同的接口,因此可以在不改變客戶端代碼的情況下,增加或修改對象的功能。

裝飾器模式的優點包括:

動態地給對象添加新的行為,而無需修改對象的源代碼或繼承結構。
可以獨立地增加對象的功能,因為每個裝飾器都是獨立的類。
保持了類的單一職責,使得代碼更易于維護和擴展。
裝飾器模式通常用于添加非核心功能,如日志、性能追蹤、緩存等,而不會影響對象的核心行為。


2.內涵


?Decorator Pattern 的主要組成部分:

  • Component(組件):這是定義對象接口的抽象類或接口。所有可以裝飾的對象都必須實現這個接口,這樣裝飾器才能與它們互換。
  • Concrete Component(具體組件):這是 Component 接口的實現,是將要被裝飾的對象。它定義了實際的行為和職責。
  • Decorator(裝飾器):這是 Component 接口的實現,它持有一個 Component 對象的引用。裝飾器可以是抽象的,也可以包含具體的行為。裝飾器對象可以添加新的行為或修改 Component 對象的行為。
  • Concrete Decorator(具體裝飾器):這是 Decorator 的具體實現,它給 Component 添加新的行為或職責。每個 Concrete Decorator 都可以添加不同的功能,也可以堆疊多個 Decorator 來增強對象的功能。

組件之間的調用圖如下圖所示:

+------------+| Component ?|+------------+|| 繼承/實現V+--------------+| ?Decorator ? |+--------------+|| 繼承/實現V+-------------------+| Concrete Decorator|+-------------------+|| 持有V+-------------------+| Concrete Component|+-------------------+


每個模塊的作用如下:

  • Component Interface:定義了公共接口,使得裝飾器和組件可以互相協作。
  • Concrete Component:實現了 Component 接口,定義了具體的行為和狀態,是被裝飾的對象。
  • Decorator:作為抽象裝飾器,持有 Component 的引用,實現 Component 接口,以保持與組件的兼容性。
  • Concrete Decorator:具體實現了裝飾器的邏輯,添加或修改了 Concrete Component 的行為。可以有多個 Concrete Decorator,每個實現不同的增強功能。

3.使用示例

#include <iostream>
#include <string>using namespace std;// Component interface - defines the basic ice cream
// operations.
class IceCream {
public:virtual string getDescription() const = 0;virtual double cost() const = 0;
};// Concrete Component - the basic ice cream class.
class VanillaIceCream : public IceCream {
public:string getDescription() const override{return "Vanilla Ice Cream";}double cost() const override { return 160.0; }
};// Decorator - abstract class that extends IceCream.
class IceCreamDecorator : public IceCream {
protected:IceCream* iceCream;public:IceCreamDecorator(IceCream* ic): iceCream(ic){}string getDescription() const override{return iceCream->getDescription();}double cost() const override{return iceCream->cost();}
};// Concrete Decorator - adds chocolate topping.
class ChocolateDecorator : public IceCreamDecorator {
public:ChocolateDecorator(IceCream* ic): IceCreamDecorator(ic){}string getDescription() const override{return iceCream->getDescription()+ " with Chocolate";}double cost() const override{return iceCream->cost() + 100.0;}
};// Concrete Decorator - adds caramel topping.
class CaramelDecorator : public IceCreamDecorator {
public:CaramelDecorator(IceCream* ic): IceCreamDecorator(ic){}string getDescription() const override{return iceCream->getDescription() + " with Caramel";}double cost() const override{return iceCream->cost() + 150.0;}
};// 測試案例分析調用
int main()
{// Create a vanilla ice creamIceCream* vanillaIceCream = new VanillaIceCream();cout << "Order: " << vanillaIceCream->getDescription()<< ", Cost: Rs." << vanillaIceCream->cost()<< endl;// Wrap it with ChocolateDecoratorIceCream* chocolateIceCream= new ChocolateDecorator(vanillaIceCream);cout << "Order: " << chocolateIceCream->getDescription()<< ", Cost: Rs." << chocolateIceCream->cost()<< endl;// Wrap it with CaramelDecoratorIceCream* caramelIceCream= new CaramelDecorator(chocolateIceCream);cout << "Order: " << caramelIceCream->getDescription()<< ", Cost: Rs." << caramelIceCream->cost()<< endl;delete vanillaIceCream;delete chocolateIceCream;delete caramelIceCream;return 0;
}

4.注意事項


在使用 Decorator Pattern 時,需要注意以下幾點:

  • 性能影響:裝飾器可能會增加對象的創建和管理成本,特別是在需要大量創建和銷毀對象的場景下。因此,需要權衡裝飾器帶來的靈活性和可能的性能損失。
  • 代碼復雜性:如果過度使用裝飾器,可能會導致代碼結構變得復雜,難以理解和維護。確保每個裝飾器都有明確的職責,并保持代碼的簡潔性。
  • 類型檢查和強類型語言:在強類型語言中,裝飾器可能會隱藏原始對象的類型,這可能導致類型檢查問題。使用類型注解或接口可以幫助解決這個問題。
  • 一致性:確保所有裝飾器的行為與組件接口保持一致,否則可能會導致客戶端代碼出錯或行為不一致。
  • 可組合性:雖然裝飾器可以堆疊,但過多的裝飾器可能導致代碼難以理解和調試。考慮使用組合模式來組合多個功能,而不是一次性添加多個裝飾器。
  • 狀態管理:如果組件的狀態對行為有影響,確保裝飾器正確處理和傳遞這些狀態,以避免意外的行為。
  • 設計時的考慮:在設計系統時,提前考慮是否需要使用裝飾器,因為它可能影響到類的設計和接口的定義。在開始編碼之前,充分理解需求和擴展性要求,以便做出最佳決策。
5.最佳實踐


該模式,最佳實踐包括以下這些點:

  • 保持裝飾器和組件接口一致:裝飾器應該與組件有相同的接口,這樣客戶端代碼可以透明地使用裝飾后的對象,而無需知道它是裝飾器還是原始組件。
  • 避免深度裝飾:雖然可以堆疊多個裝飾器,但過多的裝飾可能導致代碼復雜性增加。如果需要添加大量功能,可能需要考慮其他設計模式,如組合模式或使用類的繼承。
  • 使用接口而非具體類:裝飾器模式通常與接口一起使用,因為接口允許更靈活的替換和擴展。如果使用具體類,可能會限制裝飾器的通用性。
  • 明確職責:每個裝飾器應專注于添加或修改特定的行為,而不是試圖一次性處理所有額外功能。這樣可以保持代碼的清晰和可維護性。
  • 使用裝飾器來擴展功能:裝飾器模式最適合用于添加非核心功能,如日志、緩存、權限控制等,這些功能可以獨立于核心業務邏輯存在。
  • 避免與繼承混淆:裝飾器模式是作為繼承的替代方案,特別是當需要動態地添加或移除行為時。如果新的行為是靜態的,并且適用于所有對象,那么繼承可能更合適。
  • 測試和文檔:確保為裝飾器編寫測試用例,并在文檔中明確說明裝飾器的作用,以便其他開發者理解其功能和使用方式。
6.總結

該模式在使用時可能存在以下“坑”:類型混淆:裝飾器可能會隱藏原始對象的類型,導致類型檢查問題。例如,在強類型語言中,如果裝飾器沒有正確地保持原始類型信息,可能會在編譯時或運行時遇到錯誤。例如,Java 中的 InputStream 和其裝飾器,如果不注意類型轉換,可能會導致類型安全問題。此外,性能開銷也是需要考慮的地方。

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

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

相關文章

C 語言設計模式(行為型)

文章目錄 策略模式場景示例 迭代器模式場景示例 訪問者模式場景示例 觀察者模式場景示例 命令模式場景示例 模板方法模式場景示例 事件驅動模式場景示例 責任鏈模式場景示例 狀態模式場景示例 策略模式 策略模式&#xff08;Strategy Pattern&#xff09;是一種行為型設計模式…

銀行為什么要對網點開展神秘顧客檢測項目?

銀行業面臨的形勢復雜多變&#xff0c;包括技術創新、客戶行為變化、競爭加劇、監管環境變化、全球化與本地化平衡、經濟環境影響以及可持續發展和社會責任等多方面的挑戰和機遇。銀行需要通過種策略&#xff0c;積極應對這些變化&#xff0c;實現可持續發展。其中提升客戶服務…

順序表實現通訊錄項目

目錄 一.實現功能&#xff1a; 二.文件結構 三.代碼實現 1.初始化 2.通訊錄的銷毀 3.通訊錄添加數據 4.通訊錄刪除數據 5.通訊錄的修改 6.展現通訊錄數據 7.通訊錄查找 四.代碼 SeqList.h Contact.h Contact.c test(通訊錄).c 一.實現功能&#xff1a; ?少能夠存…

Samtec技術漫談 | 電動自行車中的傳感器和信號傳輸技術

【摘要/前言】 電動自行車&#xff0c;大家熟悉嗎&#xff1f; 今天的話題似乎是可以喚起大家心底騎車的美好回憶&#xff0c;我們也曾騎車探索過大自然和社區&#xff0c;自行車也是我們曾經不可或缺的便捷交通工具。 懷舊思潮的影響&#xff0c;加持科技的進步&#xff0c…

php 使用phpoffice導出導出excel

荊軻刺秦王 在PHP中&#xff0c;可以使用 PhpSpreadsheet 庫來創建和導出Excel文件。PhpSpreadsheet 是一個純PHP 編寫的組件庫&#xff0c;它使用現代 PHP 寫法&#xff0c;代碼質量和性能比 PHPExcel 高不少&#xff0c;完全可以替代PHPExcel&#xff08;PHPExcel已不再維護…

【HDFS】FSImage加載過程之loadINode過程

普通的loadINode方法(即不是root inode): 根據inode的類型:文件、目錄、鏈接,做不同的加載處理。 // 根據傳入的PB INode的type做不同處理。// 我們下面關注FILE和DIRECTORY兩種類型:private INode loadINode(INodeSection.INode n) {switch (n.getType()) {<

【云原生】Kubernetes中的List-Watch機制詳解與容器生命周期

目錄 引言 一、List-Watch機制概述 &#xff08;一&#xff09;基本概念 &#xff08;二&#xff09;工作機制 1.List操作 2.Watch操作 &#xff08;三&#xff09;數據流向 1.按模塊劃分 2.按整體總結 二、Pod生命周期 &#xff08;一&#xff09;生命周期 1.創建…

CMake-1 cmake簡介及安裝使用

文章目錄 1. CMake 簡單介紹2. CMake 安裝使用 1. CMake 簡單介紹 為什么需要CMake 寫過C語言的都知道&#xff0c;C語言項目使用Makefile進行管理&#xff0c;而隨著項目復雜度的增加 Makefile編寫的難度也隨之增加&#xff0c;而且在不同平臺Makefile 語法規則是不一樣的&am…

5款好用的AI寫作軟件,一鍵生成高質量文章

在當今信息快速發展的時代&#xff0c;AI寫作軟件逐漸成為創作者們的得力助手。它們能夠憑借先進的技術和算法&#xff0c;一鍵生成高質量的文章&#xff0c;為創作者們節省大量的創作時間和精力。以下是5款備受好評的AI寫作軟件&#xff0c;下面在本文中分享給大家&#xff0c…

20240522金融讀報:出口信用保險提效蘇易融碳中和機票貸款差異化投放替代數據征信培育壯大數字經濟

1、印發通知從響應速度、承保力度、承包評審要素、產業鏈范圍、定制化、線上化、便利化等方面去充分發揮出口信用保險作用。&#xff08;這也可以作為這個貸款業務擔保時的一個考慮項吧&#xff09; 2、蘇易融&#xff1a;匯集江蘇轄內特定客群信貸產品&#xff0c;可一站式查…

BitConverter類型,Byte數組與其他基本類型數據之間的轉換

BitConvert對于byte數組轉換為其他的基本變量很方便&#xff0c;是我們開發必須要學會的類型轉換&#xff0c;因為我在使用中使用的比較多&#xff0c;創作不易&#xff0c;大家點贊關注收藏。 GetBytes(XX)將基本變量轉換成字節數組&#xff0c;C#在數據存儲在計算機中的方式…

kettle學習之表的輸入輸出

需求 把表A里的數據傳送到表B中&#xff0c;在此之前&#xff0c;清空表B內的數據 表輸入 執行SQL腳本 表輸出

一文帶你學會如何部署個人博客到云服務器,并進行域名備案與解析!

哈嘍&#xff0c;大家好呀&#xff01;這里是碼農后端。之前我給大家介紹了如何快速注冊一個自己的域名&#xff0c;并創建一臺自己的阿里云ECS云服務器。本篇將介紹如何將個人博客部署到云服務器&#xff0c;并進行域名備案與解析。 1、域名備案 注冊了域名并購買了云服務器之…

探索自動化辦公的新境界:批量操作與智能管理

新書上架~&#x1f447;全國包郵奧~ python實用小工具開發教程http://pythontoolsteach.com/3 歡迎關注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目錄 一、自動化辦公的必要性與價值 二、基礎操作與自動化腳本 三、Python在自動化辦公中的應用…

Meme幣總市值突破630億美元 以太坊ETF獲批意味著代幣化資產“完全安全”

近日&#xff0c;數字貨幣市場再次掀起軒然大波。一方面&#xff0c;Meme幣總市值突破了630億美元&#xff0c;令人瞠目結舌&#xff1b;另一方面&#xff0c;以太坊ETF的獲批也引發了市場的廣泛關注&#xff0c;被視為代幣化資產的“完全安全”標志。 Meme幣總市值飆升 Meme幣…

深圳比創達電子EMC|EMC電磁兼容性行業:挑戰與機遇并存

隨著電子技術的迅猛發展&#xff0c;電磁兼容性&#xff08;EMC&#xff09;已成為各行各業不可忽視的關鍵問題。EMC是指設備或系統在其電磁環境中能正常工作且不對該環境中任何事物構成不能承受的電磁騷擾的能力。 一、EMC電磁兼容性行業的現狀 EMC電磁兼容性行業作為電子技…

[數據集][目標檢測]道路井蓋下水道井蓋開關閉和檢測數據集VOC+YOLO格式407張2類別

數據集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路徑的txt文件&#xff0c;僅僅包含jpg圖片以及對應的VOC格式xml文件和yolo格式txt文件) 圖片數量(jpg文件個數)&#xff1a;407 標注數量(xml文件個數)&#xff1a;407 標注數量(txt文件個數)&#xff1a;407 標注類別…

構建php環境、安裝、依賴、nginx配置、ab壓力測試命令

目錄 php簡介 官網php安裝包 選擇下載穩定版本 &#xff08;建議使用此版本&#xff0c;文章以此版本為例&#xff09; 安裝php解析環境 準備工作 安裝依賴 zlib-devel 和 libxml2-devel包。 安裝擴展工具庫 安裝 libmcrypt 安裝 mhash 安裝mcrypt 安裝php 選項含…

深入理解一下棧

1、棧&#xff1a;數據結構 為什么 main()方法 最先執行&#xff0c;最后結束&#xff1f; 當然是因為 main()方法入棧啦。 2、棧&#xff1a;棧內存&#xff0c;主管程序的運行&#xff0c;生命周期和現成同步&#xff1b; 線程結束&#xff0c;棧內內存也就釋放了&#xff0c…

STM32_RCC

1、RCC RCC即Reset and Clock Control&#xff0c;復位和時鐘控制。通過stm32f10x結構圖可以看出RCC控制著stm32的AHB系統總線&#xff0c;而AHB總線又橋接APB1和APB2&#xff0c;分別通過它們控制不同的片上外設。如果要使用某個片上外設的功能&#xff0c;必須先通過…