裝飾器模式

来源:http://www.cnblogs.com/glorytao/archive/2016/03/03/5239003.html
-Advertisement-
Play Games

1、概念:裝飾模式是在不必改變原類文件和使用繼承的情況下,動態的擴展一個對象的功能。它是通過創建一個包裝對象,也就是裝飾來包裹真實的對象,又叫做包裝模式。 2、在java的IO流這個章節中,我們會發現有底層流,比如說位元組和字元流,有緩衝流等等: FileOutputStream:基本的文件輸出流 B


1、概念:裝飾模式是在不必改變原類文件和使用繼承的情況下,動態的擴展一個對象的功能。它是通過創建一個包裝對象,也就是裝飾來包裹真實的對象,又叫做包裝模式。

2、在java的IO流這個章節中,我們會發現有底層流,比如說位元組和字元流,有緩衝流等等:

FileOutputStream:基本的文件輸出流 BufferedOutputStream:緩衝流 DataOutputStream :輸出二進位數據的緩衝流,這三種流我們可以隨機組合而實現不同功能

new BufferedOutputStream(new FileOutputStream):帶有緩衝流的文件輸出流

new DataOutputStream(new FileOutputStream):帶有輸出二進位數據的文件輸出流

new DataOutputStream(new BufferedOutputStream(new FileOutputStream)):帶有雙層緩衝流的可以輸出二進位數據的文件輸出流

這樣組合就實現了各種不同的功能,在IO流中大量使用了我們的裝飾模式

3、裝飾模式的角色:

抽象組件角色(Component):給出一個抽象介面,以規範準備接收附加功能的對象

具體組件角色(Concrete Component):定義一個將要接收附加功能的類

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

具體裝飾角色(Concrete Decorator):負責給構件對象貼上附加的功能

4、裝飾模式特點:

(1) 裝飾對象和被裝飾對象有相同的介面。這樣客戶端對象就可以以和被裝飾對象相同的方式和裝飾對象交互。
(2) 裝飾對象包含一個被裝飾對象的索引(reference)
(3) 裝飾對象接受所有的來自客戶端的請求。它把這些請求轉發給被裝飾的對象。
(4) 裝飾對象可以在轉發這些請求以前或以後增加一些附加功能。這樣就確保了在運行時,不用修改給定對象的結構就可以在外部增加附加的功能。在面向對象的設計中,通常是通過繼承來實現對給定類的功能擴展。

5、裝飾模式與繼承的區別:

裝飾模式 :用來擴展特定對象的功能 不需要子類 動態地 運行時分配職責 防止由於子類而導致的複雜和混亂 。對於一個給定的對象,同時可能有不同的裝飾對象,客戶端可以通過它的需要選擇合適的裝飾對象來進行裝飾,對於所有可能的組合,很容易增加

繼承:用來擴展一類對象的功能 需要子類 靜態地 編譯時分派職 缺乏靈活性 導致很多子類產生。

6、案例

package com.model.decorator;

/**
 * 抽象主題對象--飲料類
 * Created by Administrator on 2016/3/2.
 */
public abstract class Berverage {
	protected String description = "Unknow Berverage";

	public String getDescription() {
		return description;
	}

	public abstract double cost();
}
package com.model.decorator;

/**
 * 具體的被裝飾對者
 * Created by Administrator on 2016/3/2.
 */
public class Espresso extends Berverage {

	public Espresso(){
		description = "Espresso";
	}

	@Override
	public double cost() {
		return 1.99;
	}
}
package com.model.decorator;

/**
 * 調味品裝飾器,裝飾器介面類
 * Created by Administrator on 2016/3/2.
 */
public abstract class CondimentDecorator extends Berverage {
	public abstract String getDescription();
}
package com.model.decorator;

/**
 * 調味料摩卡裝飾器,繼承裝飾器介面的具體裝飾者
 * Created by Administrator on 2016/3/2.
 */
public class Mocha extends CondimentDecorator {
	Berverage berverage;

	public Mocha (Berverage berverage) {
		this.berverage = berverage;
	}

	@Override
	public String getDescription() {
		return berverage.getDescription() + ",Mocha";
	}

	@Override
	public double cost() {
		return 0.2 + berverage.cost();
	}
}
package com.model.decorator;

/**
 * 調味料Soy裝飾器,繼承裝飾器的具體裝飾者
 * Created by Administrator on 2016/3/2.
 */
public class Soy extends CondimentDecorator {
	Berverage berverage;

	public Soy (Berverage berverage) {
		this.berverage = berverage;
	}

	@Override
	public String getDescription() {
		return berverage.getDescription() + ",Soy";
	}

	@Override
	public double cost() {
		return 0.23 + berverage.cost();
	}
}
package com.model.decorator;

/**
 * Created by Administrator on 2016/3/2.
 */
public class DecoratorTest {
	public static void main(String[] args) {
		Berverage berverage = new Espresso();
		//不加任何調味料的濃咖啡
		System.out.println(berverage.getDescription() + "$" + berverage.cost());
		//添加摩卡的濃咖啡
		berverage = new Mocha(berverage);
		//添加soy的摩卡濃咖啡
		berverage = new Soy(berverage);

		//結賬
		System.out.println(berverage.getDescription() + "$" + berverage.cost());
	}
}
執行結果:
Espresso$1.99 Espresso,Mocha,Soy$2.42 Process finished with exit code 0

7、深入裝飾模式

(1)模式功能
裝飾模式能夠實現動態的為對象添加功能,是從一個對象外部來給對象增加功能,相當於是改變了對象的外觀。當裝飾過後,從外部使用系統的角度看,就不再是使用原始的那個對象了,而是使用被一系列的裝飾器裝飾過後的對象。
這樣就能夠靈活的改變一個對象的功能,只要動態組合的裝飾器發生了改變,那麼最終所得到的對象的功能也就發生了改變。
變相的還得到了另外一個好處,那就是裝飾器功能的復用,可以給一個對象多次增加同一個裝飾器,也可以用同一個裝飾器裝飾不同的對象。

(2)對象組合
前面已經講到了,一個類的功能的擴展方式,可以是繼承,也可以是功能更強大、更靈活的對象組合的方式。
其實,現在在面向對象設計中,有一條很基本的規則就是“儘量使用對象組合,而不是對象繼承”來擴展和復用功能。裝飾模式的思考起點就是這個規則,可能有些朋友還不太熟悉什麼是“對象組合”,下麵介紹一下“對象組合”。

(3)裝飾器
裝飾器實現了對被裝飾對象的某些裝飾功能,可以在裝飾器裡面調用被裝飾對象的功能,獲取相應的值,這其實是一種遞歸調用。
在裝飾器里不僅僅是可以給被裝飾對象增加功能,還可以根據需要選擇是否調用被裝飾對象的功能,如果不調用被裝飾對象的功能,那就變成完全重新實現了,相當於動態修改了被裝飾對象的功能。
另外一點,各個裝飾器之間最好是完全獨立的功能,不要有依賴,這樣在進行裝飾組合的時候,才沒有先後順序的限制,也就是先裝飾誰和後裝飾誰都應該是一樣的,否則會大大降低裝飾器組合的靈活性。

(4)裝飾器和組件類的關係
裝飾器是用來裝飾組件的,裝飾器一定要實現和組件類一致的介面,保證它們是同一個類型,並具有同一個外觀,這樣組合完成的裝飾才能夠遞歸的調用下去。
組件類是不知道裝飾器的存在的,裝飾器給組件添加功能是一種透明的包裝,組件類毫不知情。需要改變的是外部使用組件類的地方,現在需要使用包裝後的類,介面是一樣的,但是具體的實現類發生了改變。

(5)退化形式
如果僅僅只是想要添加一個功能,就沒有必要再設計裝飾器的抽象類了,直接在裝飾器裡面實現跟組件一樣的介面,然後實現相應的裝飾功能就可以了。但是建議最好還是設計上裝飾器的抽象類,這樣有利於程式的擴展。

 

  

  

  

  

  

  

  


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

-Advertisement-
Play Games
更多相關文章
  • Java8讀文件僅需一行代碼 此方法確保了當讀入文件的所有位元組內容時,文件屬性是關閉的,否則就會出現IO異常或其它的未檢查異常。這意味著在讀文件到最後的塊內容後,無需關閉文件。要註意,此方法不適合讀取很大的文件,因為可能存在記憶體空間不足的問題。開發者還應該明確規定文件的字元編碼,以避免任異常或解析錯
  • 闡述C++中多任務處理的相關概念
  • public class HttpsTest { @SuppressWarnings("deprecation") public static void main(String[] args) { try { SSLContext context = SSLContext.getInstance("
  • php中讀取文件可以使用fopen和file_get_contents這兩個函數,二者之間沒有本質區別,只是前者讀取文件的php代碼相比後者要複雜一點。本文章通過實例向大家講解fopen和file_get_contents讀取文件的實現代碼。需要的碼農可以參考一下。 fopen讀取文件的代碼如下:
  • Java 異常處理方法 Java catch多個異常處理 Java Finally實例 Java 如何使用 catch 處理異常 Java 多線程異常處理實例 Java 如何獲取異常的堆棧信息 Java 重載方法異常處理 Java 鏈試異常實例 Java 如何自定義異常處理
  • 學習maven項目時 搭建個ssm項目 算是給自己留個備份吧 環境說明: MyEclipse10 Maven 3.2.3 框架: struts2 2.3.24.1 spring3 3.0.5.RELEASE mybatis 3.2.2 資料庫: mysql 5.7 <project xmlns="h
  • 所謂“單例”: 單例模式是一種常用的軟體設計模式。在它的核心結構中只包含一個被稱為單例的特殊類。通過單例模式可以保證系統中一個類只有一個實例而且該實例易於外界訪問,從而方便對實例個數的控制並節約系統資源。如果希望在系統中某個類的對象只能存在一個,單例模式是最好的解決方案。 C#中的例子: 轉:htt
  • 1 package com.shejimoshi.behavioral.Iterator; 2 3 4 /** 5 * 功能:我們的迭代器介面 6 * 時間:2016年3月4日上午9:17:36 7 * 作者:cutter_point 8 */ 9 public interface MyIterat
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...