【設計模式】裝飾者模式-明月裝飾了你的窗子

来源:http://www.cnblogs.com/liujiong/archive/2017/09/01/7460921.html
-Advertisement-
Play Games

使用裝飾者模式,可以動態的給一個對象添加一些額外的職責。這適用於,我們只希望給某個對象而不是整個類添加一些功能的場景。通過使用含有某個特定功能的類來“包裹”原始的類,提供給原始的類某些它本身不具備的特性。比如,我們有一杯“茉莉茶”,現在加上一顆“檸檬”,那我們就有了一杯“檸檬茉莉花茶”。“檸檬”作為... ...


裝飾者模式

  使用裝飾者模式,可以動態的給一個對象添加一些額外的職責。這適用於,我們只希望給某個對象而不是整個類添加一些功能的場景。通過使用含有某個特定功能的類來“包裹”原始的類,提供給原始的類某些它本身不具備的特性。比如,我們有一杯“茉莉茶”,現在加上一顆“檸檬”,那我們就有了一杯“檸檬茉莉花茶”。“檸檬”作為一個裝飾者,提供了“茉莉茶”本身沒有的清爽口感。當然,這也帶來了一定的負擔,你需要花更多的“錢”。

 

1. 定義

  裝飾者模式動態地將職責附加到對象上。若要擴展功能,裝飾者提供了比繼承更有彈性的解決方案。

 

2. 為什麼需要

  裝飾者提供了繼承更高的靈活性。可以使用繼承來實現將父類的功能添加到子類中,但是這種方式限制了用戶選擇的權利,沒有辦法選擇將父類的哪些功能添加到子類中,只能被動的接受父類所有的功能。作為一個類而言,擁有更多的功能並不一定是件好事。所有的類都不應該試圖成為一個“全棧“。裝飾者模式則剛好提供了用戶選擇的權利,用戶可以”謹小慎微“的選擇自己需要的功能,而不用為自己不需要的功能去買單。

  該模式的實現方式,也被它的名字清楚的表達。

  裝飾。

 

3. 實現方案

   3.1 實現註意點

  1. 介面一致性。裝飾對象的介面必須與它所裝飾的類的介面是一致的。體現了“裝飾”過程不能改變對象的“本質”
  2. 省略抽象的裝飾者類。
  3. 改變對象的外殼。裝飾者Decorator可以被看做是一個對象的外殼,它可以改變對象的行為。

  3.2 實現代碼

  參與者:

  1. 一個 抽象類Tea ,用於表示茶的最頂層類。
  2. 一個具體類 JasmineTea ,表示茶的一種,茉莉茶。
  3. 一個抽象類 TeaDecorator  ,表示茶的裝飾者。用於向茶中加入不同的配料。
  4. 一個具體類 Lemon ,繼承 TeaDecorator ,表示可以向茶中加入的配料,檸檬。

 

  抽象類 Tea 實現代碼如下:

/*
    為一個抽象類,所有的茶都需要直接或間接的繼承它
 */
public abstract class Tea {

    private String description = "tea";

    public String getDescription() {
        return description;
    }
}

  

  具體類 JasmineTea 實現代碼如下:

/**
 * 現在小店只提供一種茶,茉莉茶。
 * 
 * 可以向它添加不同的茶調料,搭配不同的口味
 */
public class JasmineTea extends Tea {

    @Override
    public String getDescription() {
        return "jasmine tea";
    }
}

  小店剛開業,只提供茉莉花茶,請多擔待。不過,我們提供了配料可以搭配不同的口味。

  先需要提供一個 TeaDecorator 的抽象類,它可以提供不同的配料,實現代碼如下:

/*
    茶的裝飾者,比如涼茶,檸檬茶等
 */
public abstract class TeaDecorator extends Tea{

    public abstract String getDescription();
}

  接下來,則是本店現今提供的唯一調料,檸檬,實現代碼如下:

/*
    這是一個“茶”的裝飾者,表示在茶中加入檸檬
 */
public class Lemon extends TeaDecorator {

    private Tea tea;

    /**
     * 註意:這裡需要傳入“一杯茶”,也就是要“被裝飾”的對象
     * 這裡的語義:有一杯茶,需要向茶中加入檸檬。
     * 理所當然的,檸檬就是一個“裝飾者”
     */
    public Lemon(Tea tea) {
        this.tea = tea;
    }

    public String getDescription() {
        return "lemon " + tea.getDescription();
    }
}

  好!小店已經準備好了茶,也準備好了調料。那是時候給各位客觀端上一杯沁人心脾的“檸檬茉莉花茶”了,代碼實現如下:

public class App {

    public static void main(String[] args) {

        Tea jasmineTea = new JasmineTea(); // 先沖一杯清香的茉莉茶
        Tea lemonJasmineTea = new Lemon(jasmineTea); // 然後向茶中加入一顆檸檬

        System.out.println(lemonJasmineTea.getDescription()); // 一杯生津止渴的 “lemon jasmine tea” 就泡好了
    }
}

  端上一杯“檸檬茉莉花茶”,就著網易雲音樂,看著“四人幫”的設計模式,豈不美哉!

4. 總結  

  裝飾者的主要特點在於在不影響其他對象的情況下,可以動態的給單個對象添加職責。關於這點,我們可以參考JDK中的 java.io 包,它是使用裝飾者模式的典型場景。裝飾者模式有如下優點:

  1. 相比靜態繼承提供了更大的靈活性。它可以在運行時增加和刪除職責。此外,可以很容易的重覆添加一個特性。
  2. 避免了在層次結構高層的類有太多的特性。它不在一個類中支持所有的特性,每個裝飾者類可以只有一個特性。可以從簡單的部件複合出複雜的功能。

  使用該模式也會引入一些問題:

  1. 有許多小的對象。過多的對象會使得有些人反感,反正我個人還是挺喜歡小的函數、類、模塊...

 

  裝飾的內涵在於不改變原有本質的前提下提供原來沒有的功能。我們需要區分哪些是需要被裝飾的,而哪些是裝飾者。更多的時候是,我們裝飾著別人,同時又被別人所裝飾。

 

  正所謂:明月裝飾了你的窗子,你裝飾了別人的夢...

  好夢!


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 偽靜態 偽靜態是相對真實靜態來講的,通常我們為了增強搜索引擎的友好面,都將文章內容生成靜態頁面,但是有的朋友為了實時的顯示一些信息。或者還想運用動態腳本解決一些問題。不能用靜態的方式來展示網站內容。但是這就損失了對搜索引擎的友好面。怎麼樣在兩者之間找個中間方法呢,這就產生了偽靜態技術。就是展示出來的 ...
  • 之前在學習python的時候有整理過python異常處理的文章,不夠簡單也不夠完整,所以決定再整理一篇,算做補充。 http://www.cnblogs.com/cmt110/p/7464748.html python shell 打開一個不存在的文件abc.txt 文件,當系統找不到abc.txt ...
  • 2.copyOf:複製出新的數組,複製長度由 newLength 決定,長度可大於被覆制數組的長度 copyOfRange:複製指定下標範圍內的值 3.sort:預設進行升序排序,可自定義排序 4.toString:數組toString deepToString:二維數組toString 5.equ ...
  • list是一種有序的集合,可以隨時添加和刪除其中的元素。 知識點: . 創: 增: list是一個可變的有序表,所以,可以往list中追加元素到末尾: 也可以把元素插入到指定的位置,比如索引號為1的位置: 刪: 要刪除list末尾的元素,用pop()方法: 要刪除指定位置的元素,用pop(i)方法, ...
  • re模塊包含對 正則表達式。本章會對re模塊主要特征和正則表達式進行介紹。 什麼是正則表達式 正則表達式是可以匹配文本片段的模式。最簡單的正則表達式就是普通字元串,可以匹配其自身。換包話說,正則表達式’python’ 可以匹配字元串’python’ 。你可以用這種匹配行為搜索文本中的模式,並且用計算 ...
  • 註:本文轉載自趙學智@行勝於言《什麼是對象,為什麼要面向對象,怎麼才能面向對象?》 地址:http://www.cnblogs.com/seesea125/archive/2012/04/03/2431176.html 一、 面向對象,這個對象到底是什麼? 這個對象不是C#中的實例,C#中我們把一個 ...
  • 1.抽象的產品類 2.抽象的工廠類 3.客戶端的程式 至此,以上都是應用抽象工廠基本不變的代碼。接下來就是具體的實現類,也就是根據變化的需求給出變化的代碼 4.具體產品類 5.具體工廠類 6.應用 ...
  • 伺服器設置 1. 安裝64位JDK; 2. 設置Linux文件系統為Ext4 3.開啟2181,7771,7772防火牆埠 源碼編碼 1. 安裝Maven 2. 安裝OpenSesame 下載地址:https://github.com/alibaba/opensesame.git,將openses ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...