Java IO 裝飾者模式

来源:http://www.cnblogs.com/intsmaze/archive/2016/02/19/5202213.html
-Advertisement-
Play Games

裝飾模式(Decorator) 裝飾模式又名包裝(Wrapper)模式。 裝飾模式以對客戶端透明的方式擴展對象的功能,是繼承關係的一個替代方案。 裝飾模式通過創建一個包裝對象,也就是裝飾,來包裹真實的對象。 裝飾模式以對客戶端透明的方式動態地給一個對象附加上更多的責任。換言之,客戶端並不會覺得對象在


 

裝飾模式(Decorator)

  裝飾模式又名包裝(Wrapper)模式

  裝飾模式以對客戶端透明的方式擴展對象的功能,是繼承關係的一個替代方案。

  裝飾模式通過創建一個包裝對象,也就是裝飾,來包裹真實的對象。

  裝飾模式以對客戶端透明的方式動態地給一個對象附加上更多的責任。換言之,客戶端並不會覺得對象在裝飾前和裝飾後有什麼不同。

  裝飾模式可以在不創造更多子類的情況下,將對象的功能加以擴展。

  裝飾模式把客戶端的調用委派到被裝飾類。裝飾模式的關鍵在於這種擴展是完全透明的。

 

裝飾模式的角色

  抽象構件角色(Component):給出一個抽象介面,以規範準備接收附加責任的對象。

  具體構件角色(Concrete Component):定義將要接收附加責任的類。

  裝飾角色(Decorator):持有一個構件(Component)對象的引用,並定義一個與抽象構件介面一致的介面。

  具體裝飾角色(Concrete Decorator):負責給構件對象“貼上”附加的責任。

 

Java IO中的裝飾模式

  在IO中,具體構件角色是節點流,裝飾角色是過濾流

  FilterInputStream和FilterOutputStream是裝飾角色,而其他派生自它們的類則是具體裝飾角色。

 

裝飾模式的特點

  裝飾對象和真實對象有相同的介面。這樣客戶端對象就可以以和真實對象相同的方式和裝飾對象交互。

  裝飾對象包含一個真實對象的引用(reference)。

  裝飾對象接收所有來自客戶端的請求,它把這些請求轉發給真實的對象。

  裝飾對象可以在轉發這些請求之前或之後附加一些功能。

  這樣就確保了在運行時,不用修改給定對象的結構就可以在外部增加附加的功能。

 

程式實例

public interface Component{
        public void doSomething();
}

這是抽象構件角色,是一個介面。具體構件角色實現這個介面:

  public class ConcreteComponent implements Component{
        @Override
         public void doSomething() {
                        System.out.println("功能A");
         }
  }
 

裝飾角色:

public class Decorator implements Component{
                             private Component component;
                             public Decorator(Component component) {
                                         this.component = component;
                                    }
                             @Override
                             public void doSomething() {
                                                component.doSomething();
                                }    
}
其中包含了構件角色的引用,方法調用中利用構件角色的方法。

具體裝飾角色(兩個):

public class ConcreteDecorator1 extends Decorator{
                    public ConcreteDecorator1(Component component) {
                                super(component);
                    }
                @Override
                 public void doSomething() {
                            super.doSomething();
                            this.doAnotherThing();
                    }
                 private void doAnotherThing() {
                            System.out.println("功能B");
                    }
}
  public class ConcreteDecorator2 extends Decorator{
                 public ConcreteDecorator2(Component component) {
                             super(component);
                     }
                 @Override
                 public void doSomething() {
                         super.doSomething();
                         this.doAnotherThing();
                 }
                 private void doAnotherThing() {
                         System.out.println("功能C");
                }
}
使用測試:  

public class Client{
         public static void main(String[] args) {
                     Component component = new ConcreteComponent();
                     Component component1 = new ConcreteDecorator1(component);
                     component1.doSomething();
                     System.out.println("-----------");
                     Component component2 = new ConcreteDecorator2(component1);
                    component2.doSomething();
         }
}

問題引入

  咖啡店的類設計:

  一個飲料基類,各種飲料類繼承這個基類,並且計算各自的價錢。

  飲料中需要加入各種調料,考慮在基類中加入一些布爾值變數代表是否加入各種調料,基類的cost()中的計算各種調料的價錢,子類覆蓋cost(),並且在其中調用超類的cost(),加上特定飲料的價錢,計算出子類特定飲料的價錢。

  缺點:類數量爆炸、基類加入的新功能並不適用於所有的子類、調料價錢的改變、新調料的出現都會要求改變現有代碼;有的子類並不適合某些調料等情況……

 

設計原則

  類應該對擴展開放,對修改關閉。

  我們的目標是允許類容易擴展,在不修改現有代碼的情況下,就可搭配新的行為。

  如能實現這樣的目標,有什麼好處呢?這樣的設計具有彈性可以應對改變,可以接受新的功能來應對改變的需求。

  要讓OO設計同時具備開放性和關閉性,不是一件容易的事,通常來說,沒有必要把設計的每個部分都這麼設計。

  遵循開放-關閉原則,通常會引入新的抽象層次,增加代碼的複雜度。

  我們需要把註意力集中在設計中最有可能改變的地方,然後應用開放-關閉原則。

 

用裝飾者模式解決問題

  解決咖啡店飲料問題的方法:

  以飲料為主體,然後在運行時以調料來“裝飾”飲料。

  比如,顧客想要摩卡(Mocha)和奶泡(Whip)深焙咖啡(DarkRoast):

  DarkRoast繼承自Beverage,有一個cost()方法。

  第一步,以DarkRoast對象開始;

  第二步,顧客想要摩卡,所以建立一個Mocha裝飾者對象,並用它將DarkRoast對象包裝(wrap)起來;

  第三步,顧客想要奶泡,所以建立一個Whip裝飾者對象,並用它將Mocha對象包起來;(Mocha和Whip也繼承自Beverage,有一個cost()方法);

  最後,為顧客算錢,通過調用最外圈裝飾者(Whip)的cost()就可以。Whip()的cost()會先委托它裝飾的對象(Mocha)計算出價錢,然後在加上奶泡的價錢。Mocha的cost()也是類似。

 

裝飾者模式的特點

  裝飾者和被裝飾對象有相同的超類型

  可以用一個或多個裝飾者包裝一個對象。

  因為裝飾者和被裝飾者具有相同的類型,所以任何需要原始對象的場合,可以用裝飾過的對象代替。

  裝飾者可以在所委托被裝飾者的行為之前與/或之後,加上自己的行為,以達到特定的目的。

  對象可以在任何時候被裝飾,所以可以在運行時動態地、不限量地用你喜歡的裝飾者來裝飾對象。

 

裝飾者模式的定義

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

 

裝飾者模式的實現

  實現類圖如下:

2013-1-3 星期四 22-08-13

 

  裝飾者和被裝飾者具有共同的超類,利用繼承達到“類型匹配”,而不是利用繼承獲得“行為”;將裝飾者和被裝飾者組合時,加入新的行為。

   解決本文中飲料的具體問題時,圖中Component即為Beverage(可以是抽象類或者介面),而ConcreteComponent為各種飲 料,Decorator(抽象裝飾者)為調料的抽象類或介面,ConcreteDecoratorX則為各種具體的調料。

  因為使用對象組合,可以把飲料和調料更有彈性地加以混合與匹配。

  代碼外部細節:

  代碼中實現的時候,通過構造函數將被裝飾者傳入裝飾者中即可,如最後的調用形式如下:

    Beverage beverage = new DarkRoast();

    beverage = new Mocha(beverage);

    beverage = new Whip(beverage);

  即完成了兩層包裝,此時再調用beverage的cost()函數即可得到總價。

 

java.io包內的裝飾者模式

2013-1-3 星期四 22-27-07

  裝飾者模式的缺點:在設計中加入大量的小類,如果過度使用,會讓程式變得複雜。





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

-Advertisement-
Play Games
更多相關文章
  • 使用 HttpResponse 對象 HttpResponse 對象是與 HttpRequest 對象相對應的,用來表示構建中的響應。它當中提供了方法和屬性可供我們自定義響應,有一些在使用 MVC 視圖的時候很少使用到,但是在使用其他組件的時候可能十分有用,比如模塊是處理器。 同 HttpReque
  • HTTP請求工具類,適用於微信伺服器請求,可以自測 代碼; 1 /// <summary> 2 /// HTTP請求工具類 3 /// </summary> 4 public class HttpRequestUtil 5 { 6 #region 請求Url 7 8 #region 請求Url,不發
  • 在工作中我們經常會遇到格式轉換的問題,有的時候是將JSON轉換成DataTable、DataSet或是List等,也有可能將DataTable、DataSet或是List轉換成JSON的,抽了點時間把這些方法整合了一下,希望對大家有所幫助,如果有什麼問題請指出來,共同探討。 代碼: 1 using
  • 使用 HttpRequest 對象 HttpRequest 對象描述的是一個正在被處理的 HTTP 請求。下表列舉了 HttpRequest 中的屬性,它們提供了當前請求的相關信息(HttpRequest 類定義了一些方法和屬性,我們會逐步講解當中的一些屬性)。 表 1 – HttpRequest
  • https://msdn.microsoft.com/zh-cn/library/system.text.regularexpressions.regex(v=vs.110).aspx /// <summary> /// /// </summary> /// <param name="sender"
  • 引言--面向介面所處的設計模式中的位置。 其實,我認為Java/C#比C++高級的其中一個原因是,它對面向介面編程的支持。不要誤解,並不是說C++不支持面向介面編程,而是說C++的語法中沒有這種天然的機制。 面向對象之於面向過程,面向介面之於面向實現。但基本上,面向介面和麵向實現都基於面向對象的模式
  • Atitit.pdf 預覽 轉換html attilax總結 1. Swf flash還是html1 2. pdf2htmlEX1 3. iText 5.5.0 發佈,Java 的 PDF 操作類庫1 4. PdfBox1 5. other2 5.1. ICEpdf2 5.2. xpdf用過2 5.
  • 定義 適配器模式(Adapter):將一個類的介面轉換成客戶希望的另外一個介面 那通俗點來說,啥是適配器呢,大家都知道港版的iphone的充電器,是不能直接在內地使用的,需要一個轉換器才能使用,那麼這個 轉換器就是所謂的適配器 . 那麼適配器能夠給我們帶來什麼好處呢? 使用港版iPhone的同學都知
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...