從Java的JDK源碼中學設計模式之裝飾器模式

裝飾器模式是一種極具彈性的結構型設計模式,它允許我們通過組合的方式動態擴展對象功能而無需修改原有結構。本文將通過JDK源碼中的實際應用和通俗易懂的代碼示例,帶你深入了解這一強大模式的精髓。

裝飾器模式核心原理

裝飾器模式的核心思想:在原有對象外面"包裝"一層新功能,同時保持與被裝飾對象相同的接口。它能夠:

  1. 在不改變對象的前提下增強功能
  2. 避免因過度繼承導致類爆炸
  3. 支持運行時動態添加功能
  4. 組合替代繼承提高靈活性

Java IO包中的裝飾器模式實戰

讓我們深入JDK源碼(Java 17),看看java.io包如何完美應用裝飾器模式:

import java.io.*;public class DecoratorInJavaIO {public static void main(String[] args) throws IOException {// 基礎數據類型裝飾DataInputStream dataInput = new DataInputStream(new BufferedInputStream(new FileInputStream("data.bin")));// 字符編碼轉換裝飾BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("text.txt"), "UTF-8"));// 動態添加行號功能LineNumberReader lineReader = new LineNumberReader(reader);// 動態添加大小寫轉換裝飾器UpperCaseReader upperReader = new UpperCaseReader(lineReader);String line;while ((line = upperReader.readLine()) != null) {int num = upperReader.getLineNumber();System.out.println("Line " + num + ": " + line);}}
}// 自定義裝飾器:將內容轉為大寫
class UpperCaseReader extends FilterReader {protected UpperCaseReader(Reader in) {super(in);}@Overridepublic int read() throws IOException {int c = super.read();return (c == -1) ? c : Character.toUpperCase(c);}@Overridepublic int read(char[] cbuf, int off, int len) throws IOException {int n = super.read(cbuf, off, len);for (int i = off; i < off + n; i++) {cbuf[i] = Character.toUpperCase(cbuf[i]);}return n;}// 增強功能:提供讀取整行的方法public String readLine() throws IOException {char[] buffer = new char[1024];int pos = 0;int c;while ((c = read()) != -1) {if (c == '\n') break;buffer[pos++] = (char)c;}if (pos == 0 && c == -1) return null;return new String(buffer, 0, pos);}
}

在上述代碼中:

  1. 我們使用Java IO的核心裝飾器(BufferedInputStream, InputStreamReader
  2. 展示了裝飾器鏈式組合的強大功能
  3. 創建了自定義的裝飾器UpperCaseReader來擴展原有功能

裝飾器模式結構解析

下面使用Mermaid工具展示裝飾器模式的類圖結構:

持有引用
Component
+operation() : void
ConcreteComponent
+operation() : void
Decorator
-component: Component
+Decorator(Component)
+operation() : void
ConcreteDecoratorA
+operation() : void
+addedBehavior() : void
ConcreteDecoratorB
+addedState: String
+operation() : void

圖中關鍵角色:

  1. Component: 被裝飾對象的公共接口(如Java的InputStream)
  2. ConcreteComponent: 基礎實現(如FileInputStream)
  3. Decorator: 裝飾器抽象層(如FilterInputStream)
  4. ConcreteDecorator: 具體裝飾器實現(如BufferedInputStream)

JDK中裝飾器模式實現原理

分析java.io.FilterInputStream源碼:

public class FilterInputStream extends InputStream {protected volatile InputStream in;protected FilterInputStream(InputStream in) {this.in = in;}public int read() throws IOException {return in.read();}// 所有方法都委托給in對象public int read(byte[] b) throws IOException {return read(b, 0, b.length);}public int read(byte[] b, int off, int len) throws IOException {return in.read(b, off, len);}// 其他方法...
}

在JDK實現中:

  1. 所有具體裝飾器都繼承自FilterInputStream
  2. 每個裝飾器持有底層InputStream的引用
  3. 基礎方法直接委托給底層流
  4. 需要增強的方法被重寫(如BufferedInputStream緩沖功能)

裝飾器模式 vs 繼承

特點裝飾器模式繼承
擴展方式運行時編譯時
組合方式對象組合類繼承
靈活性高(動態組合)低(靜態綁定)
功能疊加線性添加只能單一路徑
修改風險無(不修改原類)需要修改類層次

裝飾器模式的典型應用場景

  1. 輸入/輸出流處理:Java IO/NIO中的流裝飾
  2. Servlet API:HttpServletRequestWrapper裝飾請求
  3. Collections工具類:unmodifiableXXX創建不可變視圖
  4. JavaFX應用:Node對象的多種樣式裝飾
// Java集合框架中的裝飾器應用
List<String> origin = new ArrayList<>();
List<String> safeList = Collections.checkedList(origin, String.class);
List<String> unmodifiable = Collections.unmodifiableList(origin);

裝飾器模式的優點與局限

核心優勢:

  • 符合開閉原則:擴展不修改
  • 職責明確:小類單一職責
  • 動態組合:運行時裝配功能
  • 避免類爆炸:取代多層繼承結構

潛在缺點:

  • 過度使用導致結構復雜
  • 調試困難(調用鏈路深)
  • 小對象數量可能增加

總結與最佳實踐

裝飾器模式在Java核心庫特別是IO系統中發揮了至關重要的作用。它通過優雅的包裝機制,實現了功能的動態組合,避免了傳統繼承的固有問題。

使用建議:

  1. 當需要動態、透明地添加職責時
  2. 當不適合使用子類擴展時
  3. 當目標可能有多種不同組合時
  4. 當需要保持被裝飾對象的接口純凈時

掌握裝飾器模式將使你的設計更具彈性,幫助創建更靈活、可擴展的系統架構。同時也要注意避免過度裝飾導致的復雜性,在恰當的場景發揮其最大價值。

設計思想的精髓: 組合優于繼承,封閉修改打開擴展,通過對象包裝而非類繼承來實現功能增強!

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

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

相關文章

調教 DeepSeek - 輸出精致的 HTML MARKDOWN

【序言】 不知道是不是我閑的蛋疼&#xff0c;對百度AI 和 DeepSeek 的回答都不太滿意。 DeepSeek 回答句子的引用鏈接&#xff0c;始終無法準確定位。有時鏈接只是一個域名&#xff0c;有時它給的鏈接是搜索串如: baidu.com/?q"搜索內容"。 百度AI 回答句子的引用…

第1章_數據分析認知_知識點筆記

來自&#xff1a;數據分析自學課程-戴戴戴師兄 逐字稿&#xff1a;【課程4.0】第1章_分析認知_知識點筆記 【課程4.0】第1章 分析認知 知識點總結 一、數據分析的本質認知 數據分析是什么&#xff1f; 不是酷炫看板、復雜模型或升值秘籍&#xff0c;而是認知世界的基礎方法。…

【從0-1的HTML】第2篇:HTML標簽

文章目錄 1.標題標簽2.段落標簽3.文本標簽brbstrongsubsup 4.超鏈接標簽5.圖片標簽6.表格標簽7.列表標簽有序列表ol無序列表ul定義列表dl 8.表單標簽9.音頻標簽10.視頻標簽11.HTML元素分類塊級元素內聯元素 12.HTML布局13.內聯框架13.內聯框架 1.標題標簽 標題標簽&#xff1a…

快速排序(Quick Sort)算法詳解(遞歸與非遞歸)

引言 在計算機科學中&#xff0c;排序算法是最基礎且重要的算法之一。快速排序&#xff08;Quick Sort&#xff09;作為一種高效的排序算法&#xff0c;在實際應用中被廣泛使用。平均時間復雜度為 (O(n log n))&#xff0c;最壞情況下為 (O(n^2))。本文將詳細介紹快速排序算法…

修改 vscode 左側導航欄的文字大小 (更新版)

新增, 個人常用 按 Ctrl Shift P 打開命令面板 輸入并選擇 : Developer: Toggle Developer Tools 打開開發者工具。 1. 起因&#xff0c; 目的: 問題&#xff1a; vscode 左側的文字太小了&#xff01;&#xff01;&#xff01;我最火的一篇文章&#xff0c;寫的就是這個…

Kerberos面試內容整理-Kerberos 的配置與排障

正確配置 Kerberos 對其正常工作至關重要。在Linux/Unix環境下,Kerberos配置通常通過編輯配置文件(例如 /etc/krb5.conf)完成。其中指定了Realm名稱、KDC和管理員服務器地址、默認域到Realm的映射等參數。管理員需要在KDC端初始化數據庫并創建主體(可以使用 kadmin 等工具添…

Windows + CPU也能跑時序預測:TSLib框架快速上手與踩坑避雷

在時序預測領域,選擇一個成熟的框架往往能讓我們事半功倍。最近接手了一個緊急的時序預測項目,經過一番調研后,我選擇了TSLib(Time-Series-Library)這個優秀的開源框架來快速搭建整個預測流程。 由于開發環境限制在Windows平臺且沒有GPU支持,整個部署過程還是遇到了一些…

從 0 到 1:用 Trae 插件 Builder 模式開發端午包粽子小游戲

? 前言 Trae插件獲取&#xff1a;https://www.trae.com.cn/plugin 在編程的世界里&#xff0c;效率就是生命。我們開發者常常為了一個項目的搭建&#xff0c;重復著創建文件夾、初始化項目配置、編寫樣板代碼等一系列繁瑣的操作&#xff0c;耗費了大量的時間和精力。而如今…

React-native之Flexbox

本文總結: 我們學到了 React Native 的 Flexbox 布局&#xff0c;它讓寫樣式變得更方便啦&#xff01;&#x1f60a; Flexbox 就像一個有彈性的盒子&#xff0c;有主軸和交叉軸&#xff08;行或列&#xff09;。 在 RN 里寫樣式要用 StyleSheet.create 對象&#xff0c;屬性名…

Leetcode 1336. 每次訪問的交易次數

1.題目基本信息 1.1.題目描述 表: Visits ---------------------- | Column Name | Type | ---------------------- | user_id | int | | visit_date | date | ---------------------- (user_id, visit_date) 是該表的主鍵(具有唯一值的列的組合) 該表的每行表示 use…

騰訊云國際版和國內版賬戶通用嗎?一樣嗎?為什么?

在當今全球化的數字化時代&#xff0c;云計算服務成為眾多企業和個人拓展業務、存儲數據的重要選擇。騰訊云作為國內領先的云服務提供商&#xff0c;其國際版和國內版備受關注。那么&#xff0c;騰訊云國際版和國內版賬戶是否通用&#xff1f;它們究竟一樣嗎&#xff1f;背后又…

解鎖Java多級緩存:性能飛升的秘密武器

一、引言 文末有彩蛋 在當今高并發、低延遲的應用場景中&#xff0c;傳統的單級緩存策略往往難以滿足性能需求。隨著系統規模擴大&#xff0c;數據訪問的瓶頸逐漸顯現&#xff0c;如何高效管理緩存成為開發者面臨的重大挑戰。多級緩存架構應運而生&#xff0c;通過分層緩存設…

Android Kotlin 算法詳解:鏈表相關

前言 &#x1f60a; 在 Android 開發中&#xff0c;算法與數據結構是基本功之一&#xff0c;而鏈表&#xff08;Linked List&#xff09;作為常見的數據結構&#xff0c;經常出現在各類面試題與實際業務場景中。本文將以 Android Kotlin 為語言&#xff0c;結合 LeetCode 上的…

Blinko智能筆記系統實現跨平臺同步與隱私保護的完整技術方案解析

文章目錄 前言1. Docker Compose一鍵安裝2. 簡單使用演示3. 安裝cpolar內網穿透4. 配置公網地址5. 配置固定公網地址 推薦 ? 前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。 點擊跳轉到網站 前言 是否…

【小紅書】API接口,獲取筆記列表

小紅書筆記列表API接口詳解 - 深圳小于科技助力高效數據對接 深圳小于科技&#xff08;官網&#xff1a;https://www.szlessthan.com&#xff09;提供的小紅書筆記列表API接口&#xff0c;幫助開發者快速獲取小紅書平臺筆記數據&#xff0c;實現高效內容管理與分析。 接口概述…

Qwen2.5-VL 損失函數

Qwen2.5-VL 損失函數 flyfish 文章名稱鏈接深入理解交叉熵損失 CrossEntropyLoss - 概率基礎鏈接深入理解交叉熵損失 CrossEntropyLoss - 對數鏈接深入理解交叉熵損失 CrossEntropyLoss - 概率分布鏈接深入理解交叉熵損失 CrossEntropyLoss - 信息論&#xff08;交叉熵&#…

LeetCode 1524. 和為奇數的子數組數目

好的&#xff01;讓我們詳細解釋 LeetCode 1524. 和為奇數的子數組數目 這道題的思路和解法。 題目&#xff1a; https://leetcode.cn/problems/number-of-sub-arrays-with-odd-sum/description/ 題目分析 問題描述&#xff1a; 給定一個整數數組 arr&#xff0c;返回其中和…

kafka學習筆記(三、消費者Consumer使用教程——消費性能多線程提升思考)

1.簡介 KafkaConsumer是非線程安全的&#xff0c;它定義了一個acquire()方法來檢測當前是否只有一個線程在操作&#xff0c;如不是則會拋出ConcurrentModifcationException異常。 acquire()可以看做是一個輕量級鎖&#xff0c;它僅通過線程操作計數標記的方式來檢測線程是否發…

百度蜘蛛池的作用是什么?技術@baidutopseo

百度蜘蛛池的作用 百度蜘蛛池是一種用于集中管理和調度百度搜索引擎蜘蛛&#xff08;爬蟲&#xff09;的技術工具。其主要目的是優化網站內容的收錄效率&#xff0c;幫助搜索引擎更高效地發現和抓取網頁內容。技術baidutopseo 提升收錄效率 通過集中大量百度蜘蛛的訪問請求&…

黑馬Java面試筆記之 消息中間件篇(Kafka)

一. Kafka保證消息不丟失 Kafka如何保證消息不丟失 使用Kafka在消息的收發過程中都會出現消息丟失&#xff0c;Kafka分別給出了解決方案 生產者發送消息到Brocker丟失消息在Brocker中存儲丟失消費者從Brocker接收消息丟失 1.1 生產者發送消息到Brocker丟失 設置異步發送 消息…