掌握設計模式之裝飾者模式

来源:https://www.cnblogs.com/one12138/archive/2019/07/16/11198210.html
-Advertisement-
Play Games

![](http://ww4.sinaimg.cn/large/006tNc79ly1g4ztauvhzej30p00dw45p.jpg) ## 前言 當應用開發中,我們要為一個對象在原有功能上進行擴展增強時,往往採用繼承的方式,而繼承過多時就會使得功能類更加複雜,不利於維護,而設計模式中裝飾者模式 ...


![](http://ww4.sinaimg.cn/large/006tNc79ly1g4ztauvhzej30p00dw45p.jpg) ## 前言 當應用開發中,我們要為一個對象在原有功能上進行擴展增強時,往往採用繼承的方式,而繼承過多時就會使得功能類更加複雜,不利於維護,而設計模式中裝飾者模式可以幫助我們更好對應這種場景,裝飾者模式可以做到讓對象能夠動態地進行功能擴展,而不影響其他對象. 那究竟它是如何實現的呢,又如何實際應用呢,就讓我們一起來學習下這個模式吧。 ## 模式定義 裝飾者模式屬於結構型設計模式,首先我們先瞭解下裝飾者模式的定義。 > In object-oriented programming, the decorator pattern is a design pattern that allows behavior to be added to an individual object, either statically or dynamically, without affecting the behavior of other objects from the same class. The decorator pattern is often useful for adhering to the Single Responsibility Principle, as it allows functionality to be divided between classes with unique areas of concern. 簡而言之, 裝飾者模式就是動態地為一個對象擴展額外的功能,無論是動態還是靜態,都不影響相同類的其他對象的行為, 這樣使得對象在運行時更加靈活。 裝飾者實現的方式通常為組合或者繼承,可以讓客戶端根據需求進行對應的裝飾,來達到功能增加的目標。為了簡化理解,裝飾者模式中裝飾一詞其實就是給原來的對象添加額外功能。 ## 模式結構 接下來我們看下裝飾者模式的層次結構和主要角色. ![image-20181105081809413](https://ws4.sinaimg.cn/large/006tNbRwly1fwwvgxjzzbj30fs0aht9o.jpg) * `Component` 抽象組件,最原始,核心的對象,通常為介面或者抽象類. * `ConcreteComponent` 具體組件,對 `Component` 的實現,也是需要裝飾的對象. * `Decorator` 裝飾者, 通常為抽象組件的抽象實現, 它的屬性一定有私有變數指向 `Component`. * `ConcreteDecorator` 具體裝飾對象,是 `Decorator` 的具體實現, 用於將原始,核心的方法裝飾增強的類. 從圖中看到,介面 `Component` 會有對應的實現類 `ConcerateComponent`,要對具體實現類進行功能增強,就需要對應的具體裝飾者 `ConcreteDecorator` ,它通過內部引用 `Component` 類型的 `ConcerateComponent` 對象 ,在介面方法的預設實現上,允許添加額外的邏輯和功能代碼。 ## 模式實現 現在我們用喝咖啡的例子來實現下裝飾者模式,假設我們要買一杯咖啡,需要加糖,加奶,而什麼都不加的咖啡與加奶,加糖的價格都不一樣,我們就要計算調製一杯加糖加奶的咖啡需要花費多少錢。 這裡咖啡就是我們的具體組件 `ConcerateComponent`, 奶和糖就是具體裝飾對象 `ConcreteDecorator`。 為了簡單,我們先創建一個`Component`介面類 `Drink`, 定義兩個方法用來獲得價格和描述: ![](http://ww2.sinaimg.cn/large/006tNc79ly1g4ztsfc1a7j311s082q3f.jpg) 接著,創建一個 `ConcreteComponent` 類 `Coffee` 實現 `Drink` 介面. ![](http://ww2.sinaimg.cn/large/006tNc79ly1g4ztspsoi1j311s0j60ua.jpg) 現在就需要一個抽象類 `DrinkDecorator`,用於擴展實現功能增強. ![](http://ww4.sinaimg.cn/large/006tNc79ly1g4ztt8fkmxj311s0q4ju2.jpg) 然後就是實現具體裝飾對象 `Milk` 和 `Sugar`. ![](http://ww3.sinaimg.cn/large/006tNc79ly1g4zttu0hu8j30u012edl6.jpg) 最後客戶端實現製作咖啡的動作: ![](http://ww2.sinaimg.cn/large/006tNc79ly1g4ztuahwqej316q0kkq6w.jpg) 下圖為示例的類圖: ![](http://ww4.sinaimg.cn/large/006tNc79ly1g4zsk8axpmj313e0og40u.jpg) 可以從上面例子看出,通過添加不同的材料,價格不同,並且描述信息也不一樣,並且添加順序可以動態改變,甚至不添加,讓對象變得十分靈活, 這就是裝飾者模式的精髓所在。 ## 模式使用場景 裝飾者模式同樣大量應用在 JDK 源碼中,我們經常可以看到: - JDK 的 IO 操作類, 比如 [java.io.InputStream](http://docs.oracle.com/javase/8/docs/api/java/io/InputStream.html) 體系下 `FilterInputStream` 的一系列實現類,比如 `BufferedInputStream`,`LineNumberInputStream`,`DataInpuStream`。 - [java.util.Collections#synchronizedXXX()](http://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#synchronizedCollection-java.util.Collection-) 裝飾者模式可以讓程式中對象在運行時中進行功能的增強和移除,並且採用更靈活的組合方式來進行擴展。 ## 模式的得與失 **優點**: * 在不影響其他對象的情況下,動態為單個對象新增功能。 * 裝飾類與被裝飾類 (`ConcreteComponent`) 相互獨立,互不耦合,易於擴展。 * 代替繼承方式的功能實現,減少繼承類的存在。 **缺點**: * 裝飾層次過多時會讓被裝飾的對象更複雜,不容易理解,比如使用 Java I/O 的 `DataInputStream` 對象讀取數據為 Java 基本類型值時會這樣使用: ```java DataInputStream is = new DataInputStream(new BufferedInputStream(new FileInputStream(file))); ``` * 程式中若有太多的裝飾類,理解和使用上略有難度。 ## 結語 掌握裝飾者模式的精髓在於通過一層層的包裝,讓原來對象的功能更加強大,且包裝過程是動態的,靈活可以移除的,到最後還是會調用到原對象最原始的功能。 ## 參考 * https://www.journaldev.com/1540/decorator-design-pattern-in-java-example * https://java-design-patterns.com/patterns/decorator/ * 《設計模式之禪》:https://book.douban.com/subject/4260618/ * https://javadoop.com/post/design-pattern ## 推薦閱讀 - [掌握設計模式之適配器模式](https://mp.weixin.qq.com/s?__biz=MzI3NzEwMDAwNg==&mid=2647896284&idx=1&sn=fee2c9033e4321096d6010bee3c24a50&scene=21#wechat_redirect) - [需要介面管理的你瞭解一下?](https://mp.weixin.qq.com/s/9zrcG2Bar6VkcS8brRIx2g) - [Java 之 Lombok 必知必會](https://mp.weixin.qq.com/s?__biz=MzI3NzEwMDAwNg==&mid=2647896258&idx=1&sn=2a7ade9ebac83ec39342fdcfafea5a23&scene=21#wechat_redirect) - [Java 開發看的 Scala 入門](https://mp.weixin.qq.com/s?__biz=MzI3NzEwMDAwNg==&mid=2647896264&idx=1&sn=81f55af3a8f188b5f26eca32eb3865b8&scene=21#wechat_redirect) - [Java 微服務新生代之 Nacos](https://mp.weixin.qq.com/s?__biz=MzI3NzEwMDAwNg==&mid=2647896272&idx=1&sn=616b338b93e58afcf7303a06db307a3b&scene=21#wechat_redirect)
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Spring Cloud Alibaba | Nacos配置管理 Springboot: 2.1.6.RELEASE SpringCloud: Greenwich.SR1 如無特殊說明,本系列文章全採用以上版本 [TOC] 上一篇 "《Spring Cloud Alibaba | Nacos服務註冊 ...
  • 解壓壓縮包會有一個種子文件。直接迅雷下載即可,包含了韓順平老師的java入門視頻,jdbc,jsp,servlet,oracle,hibermate,spring,SHH框架,struct,linux,等十套視頻,並且還包含了配套的源碼。迅雷下載速度很快。20兆的寬頻下載速度大概是2.3MB/s,沒 ...
  • vector 是最簡單、最常用的數據存儲形式。 vector 似乎一組可以通過索引來訪問的順序存儲的數據元素。 我們可以用 vector 名和索引號的組合來表示一個具體的數據元素 例如:v[0]是5,v[1]是7。 vector 的索引號總是從“0”開始,每次加1. vector “知道自己的大小” ...
  • 經過接近1個月的時間,ElasticSearch6.x實戰教程終於成冊。這本實戰教程小冊有很多不足(甚至可能有錯誤),也是第一次完整推出一個系列的教程。 1年前,我開始真正接觸ES,在此之前僅停留在知道的階段,甚至連瞭解都算不上。1年後跳槽,新的知識新的領域爆炸式的噴涌而出,分散式、ES、Redis ...
  • 消費組和消費者 1. 消費組和消費者是一對多的關係。 2. 同一個消費組的消費者可以消費多個分區,且是獨占的。 3. 消費者的分區分配策略由介面 定義,內置三種分配策略 、`RoundRobinAssignor StickyAssignor`,支持自定義策略。 4. 不同消費組可以消費相同的分區,互 ...
  • 題目 不同路徑 1 一個機器人位於一個 m x n 網格的左上角 (起始點在下圖中標記為“Start” )。 機器人每次只能向下或者向右移動一步。機器人試圖達到網格的右下角(在下圖中標記為“Finish”)。 問總共有多少條不同的路徑? 輸入說明 例如,上圖是一個 7 x 3 的網格。有多少可能的路 ...
  • ![img](https://mmbiz.qpic.cn/mmbiz_jpg/1flHOHZw6Rs7yEJ6ItV43JZMS7AJWoMSZtxicnG0iaE0AvpUHI8oM7lxz1rRsmaa4IfbolVRG2WQwhXrchmVWS8Q/640?tp=webp&wxfrom=5&w ...
  • 二維數組遍歷: 外迴圈控制的是二維數組的長度,其實就是一維數組的個數。 內迴圈控制的是一維數組的長度。 外迴圈控制的是二維數組的長度,其實就是一維數組的個數。 內迴圈控制的是一維數組的長度。 結果: ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...