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
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...