設計模式之裝飾者模式(三)

来源:https://www.cnblogs.com/dimple91/archive/2019/04/13/10700688.html
-Advertisement-
Play Games

歡迎大家的持續關註。上一次,我們結合第一篇推導出來的類圖,到第二篇根據類圖進行實際代碼的編寫,對裝飾者模式有了一個整體的概念以及實戰。不知道對你幫助如何呢?小編已經有門道了,看完接下來的一部分,你會恍然大悟,原來實際編碼中你一直在用裝飾者模式。 真實世界的裝飾者:Java I/O 看到標題,是不是就 ...


歡迎大家的持續關註。上一次,我們結合第一篇推導出來的類圖,到第二篇根據類圖進行實際代碼的編寫,對裝飾者模式有了一個整體的概念以及實戰。不知道對你幫助如何呢?小編已經有門道了,看完接下來的一部分,你會恍然大悟,原來實際編碼中你一直在用裝飾者模式。

真實世界的裝飾者:Java I/O

看到標題,是不是就很想往下看,到底是I/O中的什麼呢,讓你早已經擁有了裝飾者模式的實踐?就如書上給的描述,你第一次(還有第二次和第三次)看到這些API發出“哇”的驚嘆時,放心,你不是唯一收到驚嚇的人。下麵,我們馬上給出一個典型的對象集合,用裝飾這來將功能結合起來,以讀取文件數據:
image

裝飾 java.io 類


你發現了沒,java.io和之前的咖啡店其實沒有太大的差異。這裡使用了各種“輸入”流裝飾者來符合你的用途。
你會發現“輸出”流的設計方式也是一樣的。你還會發現Reader/Writer流和輸入流/輸出流的類相當類似。不過,出學過Java文件流的同學肯定知道,Java I/O也引出類裝飾者的一個“缺點”:利用裝飾者模式,常常造成設計中有大量的小類,數量實在太多,可能會造成使用此API程式員的困擾。不知道你之前有沒有搞暈過呢,小編初入Java I/O的世界的時候,很是暈頭轉向。

編寫自己的Java I/O 裝飾者

那麼,已經懂得了裝飾者的精髓,我們自己來編寫一個輸入的裝飾者如何呢?來一個小想法:編寫一個裝飾者,把輸入流內的所有大寫字元轉成小寫。趕緊行動吧。

import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;

public class LowerCaseInputStream extends FilterInputStream {

    protected LowerCaseInputStream(InputStream in) {
        super(in);
    }
    
    public int read() throws IOException {
        int c = in.read();
        return (c == -1 ? c : Character.toLowerCase((char)c));
    }
    
    public int read(byte[] b,int offset,int len) throws IOException {
        int result = in.read(b, offset, len);
        for (int i = offset; i < offset+result; i++) {
            b[i] = (byte)Character.toLowerCase((char)b[i]);
        }
        return result;
    }

}

測試你的新Java I/O 裝飾者

基於上面的裝飾者,我們來實現下功能,看是否是符合你的需求呢?

public class InputTest {

    public static void main(String[] args) throws IOException{
        int c;
        try {
            // 設置FileInoutStream,先用BufferedInputStream裝飾它,再用我們嶄新的LowerCaseInputStream過濾器裝飾它
            InputStream inputStream = new LowerCaseInputStream(
                    new BufferedInputStream(
                            new FileInputStream("test.txt")));
            
            while ((c = inputStream.read()) >= 0) {
                System.out.print((char)c);
            }
            inputStream.close();
        } catch (IOException e) {
            
        }
    }
}

// 輸入內容:
I know the Decorator Pattern and HOW it's used in the JAVA.IO package.
// 運行結果
i know the decorator pattern and how it's used in the java.io package.

恭喜你,已經喜提裝飾者模式,在設計模式的世界里又更進一步了。這裡,我們通過咖啡廳賣升級訂單系統,來瞭解裝飾者模式一步步產生的過程;再通過實際的Java API中的I/O進一步鞏固他,並用自定義的I/O功能實現,來結束此次的裝飾者模式之旅,開不開心呢?

設計箱內的工具

還是按照之前的套路,總結下工具箱內新增的工具吧

  • OO基礎 本次沒有變化

    抽象、封裝、繼承、多態

  • OO原則

    封裝變化

    多用組合,少用繼承

    針對介面編程,不針對實現編程

    為交互對象之間的松耦合設計而努力

    對擴展開放,對修改關閉(現在有了開放-關閉原則引導我們。我們會努力的設計系統,好讓關閉的部分和新擴展的部分隔離)

  • OO模式

    『策略模式』

    『觀察者模式』

    『裝飾者模式』動態地將責任附加到對象上。想要擴展功能,裝飾者提供有別於繼承的另一種選擇

遺留問題解答

哦,對了,上次還留下了一個新增的功能,在咖啡廳里顧客可以選擇小杯、中杯、大杯的需求,調料根據咖啡容量收費。例如:小中大杯的咖啡加上豆漿,分別加收0.10,、0.15、0.20。那怎麼做呢,請往下看。這裡僅列舉Soy類,其他類的代碼請移步到GitHub上查看。

public class Soy extends CondimentDecorator {

    Beverage beverage;
    
    public Soy(Beverage beverage) {
        this.beverage = beverage;
    }
    
    @Override
    public String getDescription() {
        return beverage.getDescription() + " , Soy";
    }

    @Override
    public double cost() {
        double cost = beverage.cost();
        if (beverage.getSize() == Size.TALL) {
            cost += 0.10;
        } else if (beverage.getSize() == Size.GRANDE) {
            cost += 0.15;
        } else if (beverage.getSize() == Size.VENTI) {
            cost += 0.20;
        }
        return cost;
    }

}

至此,我們又學完了一個設計模式,裝飾者模式。除了之前的要點之外,小編在這裡還得提醒下大家,裝飾者一般對組件的客戶是透明的,除非客戶程式依賴於組件的具體類型。你可以用無數個裝飾者包裝一個組件,但是這樣會導致設計中出現許多小對象,如果過度使用,會讓程式變得很複雜。所以,我們需要按需使用,而不是濫用噢。

已經陸陸續續學完了3個設計模式,不知道大家對這樣的方式有沒有不解,或者有沒有更多的建議,小編都會虛心接受。下次課程,我們學習工廠模式。

PS:代碼已經上傳,需要查看的朋友點擊此處HeadFirstDesign

推薦閱讀

設計模式之裝飾者模式(一)

設計模式之裝飾者模式(二)

愛生活,愛學習,愛感悟,愛挨踢


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

-Advertisement-
Play Games
更多相關文章
  • 最近做公司新項目用的angular7,中碰到了一個很頭疼的問題在綁定對象中的數據改變時,頁面視圖沒有跟新,需點擊頁面中的時間元素後才會更新。以前使用angularJs也經常碰到類似情況,這種時候一般的方式使使用臟檢查(Dirty checking)讓angularJs檢查綁定到視圖上的數據來實現對頁 ...
  • 這篇隨筆講講HTML5中的表單和表單的一些元素 一、表單的作用是什麼? 概念:表單在網頁中主要是負責對數據信息的採取,表單一共分成三個部分: 1、表單的標簽:這裡麵包含了處理表單的數據所用CGI程式以及數據提交到伺服器的方法。 2、表單域元素:包含著文本框,和密碼框,多行文本框,覆選框,單選框,下拉 ...
  • <!DOCTYPE html> <html> <head> <meta charset="UTF-8"/> <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale= ...
  • 在這一集我們將講到如何從安裝vue-cli開始,到新建一個本地項目,再到vscode中關於eslint的配置,以及本地項目關聯公司遠程項目的基本操作。 一,初始化本地項目 1,首先,全局安裝vue-cli 3.0 2.檢查vue-cli的版本,確定是3.0以上 3,新建一個叫question-edi ...
  • JavaScript中的函數 1. 函數的定義 兩種定義形式: 通過函數定義表達式來定義 通過函數聲明語句來定義 通過函數定義表達式來定義 通過函數聲明語句來定義 函數聲明語句定義一個函數 函數定義表達式定義一個函數 tips:以表達式方式定義的函數(特別適合用來定義那些只會用到一次的函數),函數名 ...
  • 1.什麼是跨域資源請求? https://www.cnblogs.com/niuli1987/p/10252214.html 如果兩個頁面的協議,埠(如果有指定)和功能變數名稱都相同,則兩個頁面具有相同的源。 1.1 同源策略 瀏覽器的一個安全功能,不同源的客戶端腳本在沒有明確授權的情況下,不能讀寫對方資 ...
  • 摘自:https://www.cnblogs.com/jyuf/p/7251591.html 函數都比較簡單,直接看就ok了 ...
  • MVC: MVC的全名是Model View Controller,是模型(model)-視圖(view)-控制器(controller)的縮寫,是一種軟體設計典範。它是用一種業務邏輯、數據與界面顯示分離的方法來組織代碼,將眾多的業務邏輯聚集到一個部件裡面,在需要改進和個性化定製界面及用戶交互的同時 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...