“單一職責”模式之裝飾器模式

目錄

  • “單一職責”模式
    • 裝飾器模式 Decorator
      • 引例
      • 動機 Motivation
      • 模式定義
      • 結構 Structure
      • 要點總結

“單一職責”模式

  • 在軟件組件的設計中,如果責任劃分的不清晰,使用繼承得到的結果往往是隨著需求的變化,子類急劇膨脹,同時充斥著重復代碼,這時候的關鍵是劃清責任。
  • 典型目錄
    • 裝飾器模式 Decorator
    • 橋接模式 Bridge

裝飾器模式 Decorator

引例

  1. 對于流操作,諸如文件流、網絡流、內存流等,分別對其進行諸如加密、緩存等單個或組合的操作,子類龐大。
    // 業務操作
    class Stream
    {
    public:virtual char Read(int number) = 0;virtual char Seek(int position) = 0;virtual char Write(char data) = 0;virtual ~Stream(){}
    };// 主體類
    // 文件流
    class FileStream : public Stream
    {
    public:virtual char Read(int number){// 讀文件流}virtual char Seek(int position){// 定位文件流}virtual char Write(char data){// 寫文件流}
    };
    // 網絡流
    class NetworkStream : public Stream
    {
    public:virtual char Read(int number){// 讀網絡流}virtual char Seek(int position){// 定位網絡流}virtual char Write(char data){// 寫網絡流}
    };
    // 內存流
    class MemoryStream : public Stream
    {
    public:virtual char Read(int number){// 讀內存流}virtual char Seek(int position){// 定位內存流}virtual char Write(char data){// 寫內存流}
    };//擴展操作,如加密、緩存、加密緩存
    // 加密文件流
    class CryptoFileStream : public FileStream
    {
    public:virtual char Read(int number){// 額外的加密操作FileStream::Read(number);	// 讀文件流,這種為靜態特質		}virtual char Seek(int position){// 額外的加密操作FileStream::Seek(position);	// 定位文件流}virtual char Write(char data){// 額外的加密操作FileStream::write(data);// 寫文件流}
    };
    // 加密網絡流
    class CryptoNetworkStream : public NetworkStream 
    {
    public:virtual char Read(int number){// 額外的加密操作NetworkStream ::Read(number);	// 讀網絡流		}virtual char Seek(int position){// 額外的加密操作NetworkStream ::Seek(position);	// 定位網絡流}virtual char Write(char data){// 額外的加密操作NetworkStream ::write(data);// 寫網絡流}
    };// 緩存文件流
    class BufferedFileStream : public FileStream
    {
    public:virtual char Read(int number){// 額外的緩存操作FileStream::Read(number);	// 讀文件流		}virtual char Seek(int position){// 額外的緩存操作FileStream::Seek(position);	// 定位文件流}virtual char Write(char data){// 額外的緩存操作FileStream::write(data);// 寫文件流}
    };
    // 緩存網絡流
    class BufferedNetworkStream : public NetworkStream 
    {
    public:virtual char Read(int number){// 額外的緩存操作NetworkStream ::Read(number);	// 讀網絡流		}virtual char Seek(int position){// 額外的緩存操作NetworkStream ::Seek(position);	// 定位網絡流}virtual char Write(char data){// 額外的緩存操作NetworkStream ::write(data);// 寫網絡流}
    };// 加密緩存文件流
    class CryptoBufferedFileStream : public FileStream
    {
    public:virtual char Read(int number){// 額外的加密操作// 額外的緩存操作FileStream::Read(number);	// 讀文件流		}virtual char Seek(int position){// 額外的加密操作// 額外的緩存操作FileStream::Seek(position);	// 定位文件流}virtual char Write(char data){// 額外的加密操作// 額外的緩存操作FileStream::write(data);// 寫文件流}
    };
    // 加密網絡流
    class CryptoBufferedNetworkStream : public NetworkStream 
    {
    public:virtual char Read(int number){// 額外的加密操作// 額外的緩存操作NetworkStream ::Read(number);	// 讀網絡流		}virtual char Seek(int position){// 額外的加密操作// 額外的緩存操作NetworkStream ::Seek(position);	// 定位網絡流}virtual char Write(char data){// 額外的加密操作// 額外的緩存操作NetworkStream ::write(data);// 寫網絡流}
    };void Process()
    {// 編譯時裝配CryptoFileStream *cfs1 = new CryptoFileStream();BufferedFileStream* bfs1 = new BufferedFileStream();CryptoBufferedFileStream* cbfs1 = new CryptoBufferedFileStream();
    }
    

在這里插入圖片描述
如第二層m種變化類型,第三層n種變化類型,類的個數 :1+ m + m * n!/ 2

  1. 對第一版代碼進行重構

    // 業務操作
    class Stream
    {
    public:virtual char Read(int number) = 0;virtual char Seek(int position) = 0;virtual char Write(char data) = 0;virtual ~Stream(){}
    };// 主體類
    // 文件流
    class FileStream : public Stream
    {
    public:virtual char Read(int number){// 讀文件流}virtual char Seek(int position){// 定位文件流}virtual char Write(char data){// 寫文件流}
    };
    // 網絡流
    class NetworkStream : public Stream
    {
    public:virtual char Read(int number){// 讀網絡流}virtual char Seek(int position){// 定位網絡流}virtual char Write(char data){// 寫網絡流}
    };
    // 內存流
    class MemoryStream : public Stream
    {
    public:virtual char Read(int number){// 讀內存流}virtual char Seek(int position){// 定位內存流}virtual char Write(char data){// 寫內存流}
    };//擴展操作,如加密、緩存、加密緩存
    // 加密文件流
    class CryptoStream : public Stream
    {// FileStream* stream; 不必現在確定類型Stream* stream;// = new FileStream(); 未來確實,即運行時確定
    public:CryptoStream(Stream* st) : stream(st){}virtual char Read(int number){// 額外的加密操作stream->Read(number);	// 讀流		}virtual char Seek(int position){// 額外的加密操作stream->Seek(position);	// 定位流}virtual char Write(char data){// 額外的加密操作stream->write(data);// 寫流}
    };
    // 加密網絡流
    class CryptoNetworkStream : public Stream 
    {// NetworkStream * stream; 不必現在確定類型Stream* stream;// = new NetworkStream (); 未來確實,即運行時確定virtual char Read(int number){// 額外的加密操作stream->Read(number);	// 讀網絡流		}virtual char Seek(int position){// 額外的加密操作stream->Seek(position);	// 定位網絡流}virtual char Write(char data){// 額外的加密操作stream->write(data);// 寫網絡流}
    };
    // 加密文件流/網絡流,合并為加密流CryptoStream,結構如下方緩存流// 緩存流
    class BufferedStream : public Stream
    {Stream* stream;
    public:BufferedStream(Stream* st) : stream(st){}virtual char Read(int number){// 額外的加密操作stream->Read(number);	// 讀流		}virtual char Seek(int position){// 額外的加密操作stream->Seek(position);	// 定位流}virtual char Write(char data){// 額外的加密操作stream->write(data);// 寫流}
    };void Process()
    {// BufferedFileStream* bfs1 = new BufferedFileStream();	// 代碼1// CryptoBufferedFileStream* cbfs1 = new CryptoBufferedFileStream();	// 代碼1// 運行時裝配FileStream* fs1 = new FileSteam();CryptoStream* cfs1 = new CryptoStream(fs1);BufferedStream* bfs1 = new BufferedStream(fs1);CryptoStream* cbfs1 = new CryptoStream(bfs1);}
    
  2. 對第二部分代碼,繼續重構,將共有部分加入到裝飾類:DecoratorStream

    // 業務操作
    class Stream
    {
    public:virtual char Read(int number) = 0;virtual char Seek(int position) = 0;virtual char Write(char data) = 0;virtual ~Stream(){}
    };// 主體類
    // 文件流
    class FileStream : public Stream
    {
    public:virtual char Read(int number){// 讀文件流}virtual char Seek(int position){// 定位文件流}virtual char Write(char data){// 寫文件流}
    };
    // 網絡流
    class NetworkStream : public Stream
    {
    public:virtual char Read(int number){// 讀網絡流}virtual char Seek(int position){// 定位網絡流}virtual char Write(char data){// 寫網絡流}
    };
    // 內存流
    class MemoryStream : public Stream
    {
    public:virtual char Read(int number){// 讀內存流}virtual char Seek(int position){// 定位內存流}virtual char Write(char data){// 寫內存流}
    };//擴展操作,如加密、緩存、加密緩存
    DecoratorStream : public Stream
    {
    protected:Stream* stream;DecoratorStream(Stream* st) : stream(st){}
    }// 加密文件流
    class CryptoStream : public DecoratorStream
    {
    public:CryptoStream(Stream* st) : DecoratorStream(st){}virtual char Read(int number){// 額外的加密操作stream->Read(number);	// 讀流		}virtual char Seek(int position){// 額外的加密操作stream->Seek(position);	// 定位流}virtual char Write(char data){// 額外的加密操作stream->write(data);// 寫流}
    };// 緩存流
    class BufferedStream : public DecoratorStream
    {
    public:BufferedStream(Stream* st) : stream(st){}virtual char Read(int number){// 額外的加密操作stream->Read(number);	// 讀流		}virtual char Seek(int position){// 額外的加密操作stream->Seek(position);	// 定位流}virtual char Write(char data){// 額外的加密操作stream->write(data);// 寫流}
    };void Process()
    {// 運行時裝配FileStream* fs1 = new FileSteam();CryptoStream* cfs1 = new CryptoStream(fs1);BufferedStream* bfs1 = new BufferedStream(fs1);CryptoStream* cbfs1 = new CryptoStream(bfs1);}
    

在這里插入圖片描述
類的個數: 1 + m + 1 + n,使用組合(裝飾器類中含有被修飾類的指針),來減少類的數量。

動機 Motivation

  • 在某些情況下,我們可能會“過度地使用繼承來擴展對象的功能”,由于繼承為類型引入的靜態特質,使得這種擴展方式缺乏靈活性;并且隨著子類的增多(擴展功能的增多),各種子類的組合(擴展功能的組合)會導致更多子類的膨脹。

模式定義

動態(組合)地給一個對象增加一些額外的職責。就增加功能而言,Decorator模式比生成子類(繼承)更為靈活(消除重復代碼及減少子類個數)。

結構 Structure

在這里插入圖片描述
紅色為穩定部分,藍色為變化部分。

要點總結

  • 通過采用組合而非繼承的手法,裝飾器模式實現了在運行時動態擴展對象功能的能力,而且可以根據需要擴展多個功能,避免了使用繼承帶來的“靈活性差”和“多子類衍生”問題。
  • Decorator 裝飾器類在接口上表現為 is-a Component 的繼承關系,即Decorator裝飾器類繼承了Component 所具有的接口;但在實現上又表現為 has-a Component的組合關系,即Decorator裝飾器類又使用了另外一個Component類。
  • 裝飾器模式的目的并非解決“多子類衍生的多繼承”問題,其應用的要點在于解決“主體類在多個方向上的擴展功能”——是為“裝飾”的含義。

來源:極客班——C++設計模式入門

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

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

相關文章

idea, CreateProcess error=206, 文件名或擴展名太長

idea, CreateProcess error206, 文件名或擴展名太長 解決 “CreateProcess error206, 文件名或擴展名太長” 錯誤 CreateProcess error206 是 Windows 系統特有的錯誤,表示命令行參數超出了 Windows 的 32767 字符限制。這個問題在 Java 開發中尤其常見&#xff0c…

一鍵高效率圖片MD5修改工具PHP版

文章目錄 圖片MD5修改工具項目簡介功能特點技術原理系統需求安裝方法使用方法Web界面模式命令行模式文件結構常見問題注意事項開發者信息效果演示更多干貨??1.如果我的博客對你有幫助、如果你喜歡我的博客內容,請 “??點贊” “??評論” “??收藏” 一鍵三連哦!2.??…

跨主機用 Docker Compose 部署 PostgreSQL + PostGIS 主從

q下面是跨主機用 Docker Compose 部署 PostgreSQL PostGIS 主從復制的完整詳細步驟(主庫 從庫),主從都用官方 PostGIS 鏡像 postgis/postgis:15-3.3,并注意網絡與持久化。復制即可。 🚩 跨主機 PostgreSQL PostGIS …

會議動態|千眼狼高速攝像機、DIC測量系統等科學儀器亮相第十五屆全國爆炸力學學術會議

第十五屆全國爆炸力學學術會議于6月28日在紹興盛大召開,會議匯聚來自全國爆炸力學與沖擊領域專家學者2000余人,聚焦“爆炸與沖擊動力學工程應用”、“材料動態力學行為與損傷斷裂“、“工程爆破與毀傷評估”、“含能材料與水中爆炸”、“結構動態響應與安…

vscode一個文件夾有殘余的git倉庫文件,已經失效了,怎樣進行清空倉庫殘余文件并重新初始化git--ubuntu

vscode一個文件夾有殘余的git倉庫文件,已經失效了,怎樣進行清空倉庫殘余文件并重新初始化git–ubuntu 首先要把工作區里重要的文件備份好,防止操作時數據丟失。刪除.git文件夾 rm -rf .git初始化 (base) zd4090zd4090-System-Product-Name:…

6月30日作業

思維導圖 一、讀取文件&#xff0c;效果類似 cat 的功能 代碼 #include <25041head.h>int main(int argc, const char *argv[]) {//打開文件printf("請輸入你要讀取的文件路徑&#xff1a;");char str[128]"";scanf("%s",str);FILE *fpf…

ubuntu源碼安裝python3.13遇到Could not build the ssl module!解決方法

我在Ubuntu 24.04.2 LTS下載源碼安裝Python 3.13.5時&#xff1a; #./configure --enable-loadable-sqlite-extensions --enable-optimizations #make 顯示錯誤信息&#xff1a; Could not build the ssl module! Python requires a OpenSSL 1.1.1 or newer 查詢我的openssl版…

Ai工具分享(2):Vscode+Cline無限免費的使用教程

大家好,我是程序員寒山。 今天給大家分享一個最新的免費使用的Ai插件Cline的方法,之前也給大家分享過一些免費的方案,但是這些都是隨時在變化,之前推薦的很多都不能使用了。 Ai工具分享(2):Vscode+Cline無限免費的使用教 今天再給大家推薦一個,可以免費使用,且沒有token…

Docker 目錄遷移腳本【Windows Junction 類型鏈接】

Docker 目錄遷移腳本完整教程&#xff1a;從誕生到自動化使用 一、腳本誕生背景與開發歷程 1. 為什么需要遷移 Docker 目錄&#xff1f; 系統盤空間壓力&#xff1a;Docker 鏡像和容器數據通常存儲在C:\Users\用戶名目錄下&#xff0c;隨著使用時間增長會占用大量系統盤空間…

spring-ai 工作流

目錄 工作流概念工作流程圖spring-boot 編碼定義節點 (Node)定義節點圖StateGraphcontroller測試瀏覽器測試用戶輸入 工作流概念 工作流是以相對固化的模式來人為地拆解任務&#xff0c;將一個大任務拆解為包含多個分支的固化流程。工作流的優勢是確定性強&#xff0c;模型作為…

重頭開始學ROS(6)---Eigen庫安裝與使用

Eigen庫 矩陣運算是一種非常重要的運算方式&#xff0c;在Matlab中&#xff0c;矩陣運算可以輕松的實現&#xff0c;但在C這種偏底層的語言中&#xff0c;若不借助第三方庫&#xff0c;矩陣運算需要我們進行較為復雜的代碼設計。Eigen庫是一個用于線性運算的C模板庫&#xff0…

【STM32】外部中斷

STM32 外部中斷&#xff08;EXTI&#xff09;概述 這篇文章結合示例代碼&#xff0c;系統性地講述 STM32 外部中斷&#xff08;EXTI&#xff09;實驗的原理、以及配置流程。目的在于輔助讀者掌握STM32F1 外部中斷機制。 STM32F1xx官方資料&#xff1a;《STM32中文參考手冊V10》…

LeetCode Hot100 算法題 (矩陣篇)

1、73. 矩陣置零 給定一個 m x n 的矩陣&#xff0c;如果一個元素為 0 &#xff0c;則將其所在行和列的所有元素都設為 0 。請使用 原地 算法。 示例 1&#xff1a; 輸入&#xff1a;matrix [[1,1,1],[1,0,1],[1,1,1]] 輸出&#xff1a;[[1,0,1],[0,0,0],[1,0,1]]// 將第一行…

Flutter基礎(項目創建)

一、使用命令行創建項目 1. 確認 Flutter 環境正常 要保證 Flutter SDK 已經正確安裝&#xff0c;并且環境變量配置無誤。可以通過執行以下命令來驗證&#xff1a; flutter doctor 要保證所有檢查項都顯示綠色對勾&#xff0c;要是有問題&#xff0c;可按照提示進行修復。 …

【Actix Web】Rust Web開發實戰:Actix Web框架全面指南(2025企業級應用版)

? 在2025年高并發、低延遲成為Web服務核心指標的背景下&#xff0c;??Actix Web憑借異步Actor模型與零成本抽象??&#xff0c;成為Rust生態中生產環境部署率最高的Web框架。本指南深入解析Actix Web 4.0核心技術&#xff0c;覆蓋??百萬級并發架構設計??、??內存安全…

HTML之常用基礎標簽

HTML之常用基礎標簽 一、HTML文檔基本結構標簽1. <html>標簽2. <head>標簽3. <body>標簽 二、文本相關基礎標簽1. 標題標簽&#xff08;<h1> - <h6>&#xff09;2. 段落標簽&#xff08;<p>&#xff09;3. 換行標簽&#xff08;<br>…

外鍵列索引優化:加速JOIN查詢的關鍵

在使用數據庫時&#xff0c;特別是在執行涉及JOIN操作的查詢時&#xff0c;優化外鍵列的索引是非常重要的。外鍵通常用于建立表之間的關聯&#xff0c;而JOIN操作則是基于這些外鍵列來實現的。下面是一些關鍵步驟和技巧&#xff0c;可以幫助你優化外鍵列的索引&#xff0c;從而…

2025年 UI 自動化框架使用排行

??親愛的技術愛好者們,熱烈歡迎來到 Kant2048 的博客!我是 Thomas Kant,很開心能在CSDN上與你們相遇~?? 本博客的精華專欄: 【自動化測試】 【測試經驗】 【人工智能】 【Python】 </

【軟考高項論文】論信息系統項目的整體管理

摘要 在信息系統項目的管理中&#xff0c;整體管理處于核心地位&#xff0c;對項目全局規劃與協調起著關鍵作用&#xff0c;保障項目各階段目標一致且高效執行。本文結合作者參與的 2024 年 6 月啟動的信息系統項目&#xff0c;深入探討項目整體管理的過程&#xff0c;著重闡述…

(4)Wireshark捕獲設置

1.簡介 WireShark的強大之處就在于不用你再做任何配置就可以抓取http或者https的包。主要是講解和分享如何使用WireShark抓包。 2.運行Wireshark 安裝好 Wireshark 以后&#xff0c;就可以運行它來捕獲數據包了。方法如下&#xff1a; 1.在 Windows 的“開始”菜單中&#…