java經典設計模式4,JAVA設計模式(4) 之裝飾設計模式

在現實生活中我們的汽車都具備跑的功能,我們可以不改變汽車原有功能的前提下,把它放入一個裝修廠,開進去讓里面給咱們的車子做一些裝飾,開出來之后呢,就具備了上天的功能了(技術可達是可以的哈),這就給原來的汽車對象,增加了額外的功能。

再舉一個例子:假設我們非常愛惜一張照片,我們可以不改變照片本身前提下,給它增加一個相框,使得它具有防潮的功能,而且用戶可以根據需要給它增加不同類型的相框,甚至可以在一個小相框的外面再套一個大相框。這就是針對照片這個對象的裝飾,在軟件工程中,同樣存在類似的功能,使用裝飾模式可以透明的增加指定對象的功能。

1、裝飾模式的引入

首先咱們來看一段代碼:

假設我要設計一個汽車類,然后在里面定義了汽車可能存在的功能(后面我還要擴展汽車的功能):

public class Car {

public void run(){

System.out.println("能跑");

}

public void fly(){

System.out.println("能飛");

}

public void sweep(){

System.out.println("能游");

}

public void show(){

System.out.println("該汽車擁有的功能:");

this.run();

this.fly();

this.sweep();

}

}

public class Main {

public static void main(String[] args) {

Car bus = new Car();

bus.show();

}

}

這段代碼并沒有什么設計可言的。運行結果就不貼出來了,可見,我們在客戶端造了一個巴士,調用了巴士的 show 方法后,發現有一些功能并不是巴士的(飛、游泳),這樣顯然是存在問題的。那么我們可能會作如下修改:

使用繼承,每個繼承體系歸類。

//接口可以改為抽象類

public interface Car {

//只要是有汽車,都具備跑的功能

void run();

//調用展示該汽車存在的功能

void show();

}

public class RunCar implements Car{

//普通汽車只具備跑的功能

public void run() {

System.out.println("可以跑");

}

public void show() {

this.run();

}

}

public class FlyCar implements Car {//擴展的汽車具備飛的功能

@Override

public void run() {

System.out.println("可以跑");

}

// 定義自己的功能

public void fly() {

System.out.println("可以飛");

}

@Override

public void show() {

this.run();

this.fly();

}

}

public class SwimCar implements Car{//擴展的汽車具備游泳的功能

@Override

public void run() {

System.out.println("可以跑");

}

public void swim(){

System.out.println("可以游泳");

}

@Override

public void show() {

this.run();

this.swim();

}

}

然后在客戶端調用:

public class Main {

public static void main(String[] args) {

Car bus = new RunCar();

bus.show();

Car flyCar = new FlyCar();

flyCar.show();

}

}

運行結果如下:

ab9d20c23869226e15ad7174d6662d44.png

我們這里使用繼承的方式來擴展系統(Car)的功能,這樣擁有了設計可言,但是還是存在問題的。問題在于如果增加子類,他擁有“遁地”的功能的話(當然技術先進可以做到哈,不要在意這些細節),仍然要在遁地這個子類里面定義額外的“遁地”方法。這個時候,為了解決這種繼承擴展功能問題,就引入了本節的內容——裝飾模式。裝飾模式是擴展系統功能的最佳選擇。裝飾模式是對已有對象的功能進行擴展(裝修、裝飾),以獲得更加符合用戶需求的對象,使得對象具有更加強大的功能。

2、裝飾模式概述

裝飾模式可以在不改變一個對象本身功能的基礎上給對象增加額外的新行為,在現實生活中,這種情況也到處存在,例如裝修窗戶,我們可以不改變窗戶本身,給它增加一些額外的裝飾(比如窗花),增加他的可觀賞性,而且用戶可以根據需要給它增加不同類型的窗花,甚至可以裝飾多層。

裝飾模式是一種用于替代繼承的技術,它通過一種無須定義子類的方式來給對象動態增加職責,使用對象之間的關聯關系取代類之間的繼承關系。在裝飾模式中引入了裝飾類,在裝飾類中既可以調用待裝飾的原有類的方法,還可以增加新的方法,以擴充原有類的功能。

裝飾模式定義如下:

動態地給一個對象增加一些額外的職責,就增加對象功能來說,裝飾模式比生成子類實現更為靈活。裝飾模式是一種對象結構型模式。

在裝飾模式中,為了讓系統具有更好的靈活性和可擴展性,我們通常會定義一個抽象裝飾類,而將具體的裝飾類作為它的子類,裝飾模式結構如圖所示:

82c07b801f1a6a93e6888c1f65326caf.png

在裝飾模式結構圖中包含如下幾個角色:

Component(抽象構件):它是具體構件和抽象裝飾類的共同父類,聲明了在具體構件中實現的業務方法,它的引入可以使客戶端以一致的方式處理未被裝飾的對象以及裝飾之后的對象,實現客戶端的透明操作。【上述 Car 就是這個角色】

ConcreteComponent(具體構件):它是抽象構件類的子類,用于定義具體的構件對象,實現了在抽象構件中聲明的方法,裝飾器可以給它增加額外的職責(方法)。【上述 RunCar 就是這個角色】

Decorator(抽象裝飾類):它也是抽象構件類的子類,用于給具體構件增加職責,但是具體職責在其子類中實現。它維護一個指向抽象構件對象的引用,通過該引用可以調用裝飾之前構件對象的方法,并通過其子類擴展該方法,以達到裝飾的目的。比如針對開頭的案例,它可以對 Car 增加除了跑額外的功能 “可以游泳”、“下水”、“遁地”等。

ConcreteDecorator(具體裝飾類):它是抽象裝飾類的子類,負責向構件添加新的職責。每一個具體裝飾類都定義了一些新的行為,它可以調用在抽象裝飾類中定義的方法,并可以增加新的方法用以擴充對象的行為。【上述 FlyCar 和 SwinCar 可以作為整個角色對 Car 動能進行擴展】

由于具體構件類和裝飾類都實現了相同的抽象構件接口,因此裝飾模式以對客戶透明的方式動態地給一個對象附加上更多的責任,換言之,客戶端并不會覺得對象在裝飾前和裝飾后有什么不同。裝飾模式可以在不需要創造更多子類的情況下,將對象的功能加以擴展。

裝飾模式的核心在于抽象裝飾類的設計,其典型代碼如下所示:

class Decorator implements Component{

//持有抽象構件的引用

private Component component;

//注入一個抽象構件類型的對象(依賴倒置)

public Decorator(Component component) {

this.component=component;

}

public void operation(){

//調用原有業務方法

component.operation();

}

}

在抽象裝飾類 Decorator 中定義了一個 Component 類型的對象 component,維持一個對抽象構件對象的引用,并可以通過構造方法或 Setter 方法將一個 Component 類型的對象注入進來,同時由于 Decorator 類實現了抽象構件 Component 接口,因此需要實現在其中聲明的業務方法 operation(),需要注意的是在 Decorator 中并未真正實現 operation() 方法,而只是調用原有 component 對象的 operation() 方法,它沒有真正實施裝飾,而是提供一個統一的接口,將具體裝飾過程交給子類完成。

在 Decorator 的子類即具體裝飾類中將繼承 operation() 方法并根據需要進行擴展,典型的具體裝飾類代碼如下:

class ConcreteDecorator extends Decorator{

public ConcreteDecorator(Component component){

super(component);

}

public void operation(){

super.operation(); //調用原有業務方法

addedBehavior(); //調用新增業務方法

}

//新增業務方法

public void addedBehavior(){

……

}

}

在具體裝飾類中可以調用到抽象裝飾類的 operation() 方法,同時可以定義新的業務方法,如 addedBehavior()。

由于在抽象裝飾類 Decorator 中注入的是 Component 類型的對象,因此我們可以將一個具體構件對象注入其中,再通過具體裝飾類來進行裝飾;此外,我們還可以將一個已經裝飾過的 Decorator 子類的對象再注入其中進行多次裝飾,從而對原有功能的多次擴展。

3、裝飾模式實戰

針對文章開頭處的案例,使用裝飾設計模式進行修改。

對于裝飾模式,可以難于理解的地方在于 Decorator 抽象裝飾類為何會繼承或者實現 Component 抽象構建類。如果我們不繼承 Component 構建類使用裝飾模式的時候,代碼如下:

UML圖:

7c06c077da7d6ce803b1aa3c7bda55da.png

代碼:

```java

//Component抽象構件角色

public interface Car {

//只要是有汽車,都具備跑的功能

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/382985.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/382985.shtml
英文地址,請注明出處:http://en.pswp.cn/news/382985.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

java讀取gxk文件,Java中常見的IO流及其使用

Java中IO流分成兩大類,一種是輸入流,所有的輸入流都直接或間接繼承自InputStream抽象類,輸入流作為數據的來源,我們可以通過輸入流的read方法讀取字節數據;另一種是輸出流,所有的輸出流都直接或間接繼承自O…

matlab+voronoin函數,在Voronoi區域中生成隨機點,并創建具有高維數據的Voronoi區域...

我正在使用k-means聚類算法,并且對于每個聚類質心,我試圖為質心生成n維Voronoi區域 . 之后我需要從Voronoi區域生成隨機點 .我已經嘗試使用Matlab / Octave和scipy來獲得n維Voronoi區域 . 但我有兩個問題 .生成頂點和區域后,如何從區域生成隨…

matlab雙縱軸刻度覆蓋問題,求助: matlab雙縱軸換圖問題

非常感謝!不過,y2的范圍是-1*(10^6),7*(10^6),但是不等分:(把y1的范圍調成0.4:0.2:5.8也有28個元素,然后y2也有28個元素,但是不等分,是個曲線,而且,這個曲線的值與y1是有關的。數據見附件syms d…

php最新圖片漏洞,2018最新PHP漏洞利用技巧

本文學習了幾種新式的php exploit方法,在此做一筆記文件刪除漏洞, unlink()Phar 反序列化, file*()PHP對象實例化, ReflectionClass()0x01 WordPress Design Flaw Leads to WooCommerce RCEWooCommerce 3.4.6本版本之前存在任意刪除漏洞,因為WordPress的…

php v-for=,Vue中v-for循環節點的實現代碼

本篇文章給大家帶來的內容是關于Vue中v-for循環節點的實現代碼,有一定的參考價值,有需要的朋友可以參考一下,希望對你有所幫助。Title父循環第一次子循環第一次json數據的第幾條數值{{index}}{{indo}}{{bp.index}}{{bp.childName}}let ernew …

matlab尋找向量最小值,matlab – 在排序向量中快速搜索大于x的最小值

由于輸入已經排序,自定義二進制搜索應該有效(您可能需要對邊緣情況進行一些更新,即請求的值小于數組的所有元素):function [result, res2] binarySearchExample(val)%// Generate example data and sort itN 100000000;a rand(N, 1);a sort(a);%// Run the algo…

搜matlab代碼的網站,LTE小區搜索matlab仿真

【實例簡介】LTE小區搜索過程的matlab仿真,比較詳細,內容不錯【實例截圖】【核心代碼】35738649matlab└── matlab├── Bc.m├── CellSearch.m├── PSS_detection_correction.m├── Tc.m├── absx2.m├── add_header_to_bin.m├── add_h…

php過氣了嗎,留幾手 留幾手過氣原因

1、很多時候,人們做事情只是為了自己,沒有任何理由,沒有任何結果,只是為了滿足一些內心的期望。2、太理智的人,往往愛到一半,本能地退卻。唯一突出的是他的JB。3、怎樣才能自由地睡去女文藝青年&#xff1f…

live2d PHP,Live2dHistoire_setting.php

if(!defined(EMLOG_ROOT)) {exit(error!);}function plugin_setting_view(){$live2d_setunserialize(ltrim(file_get_contents(dirname(__FILE__)./live2d.com.php),<?php die; ?>));?>KEY&#xff1a;音樂1&#xff1a;音樂2&#xff1a;音樂3&#xff1a;音樂4&a…

mysql 遠程load data,PyMySQL將(文件)數據加載到遠程MySQL實例時發生錯誤/異常

我正在使用PyMySQL-0.5.0并在將數據從文件加載到遠程MySQL實例時遇到了一個模糊的錯誤/異常。在執行“loaddatalocalinfile…”語句時&#xff0c;我看到一個異常&#xff0c;它說&#xff1a;The used command is not allowed with this MySQL version。在如果PyMySQL支持此操…

matlab頻率阻抗,有分析阻抗的matlab腳本嗎?

以上來自于谷歌翻譯以下為原文Interesting...- You cross-posted to two forums. I have deleted the other post.- You dont indicate what scope you are using or what you have tried.Most Keysight (and Agilent) scopes have an FFT or Spectrum function available. Hav…

php中修改彈窗的樣式,CSS變形彈窗效果示例

大家都知道&#xff0c;彈出窗體已經是現在網頁常用的一種交互設計&#xff0c;在這個注重交互動畫體驗的時代&#xff0c;網頁彈窗也是可以來點新鮮點子的&#xff0c;比如今天分享的CSS 變形Modal Window。當用戶點擊按鈕時&#xff0c;按鈕將會變成一個全屏的屏幕&#xff0…

php 開發高德地圖地理圍欄,高德地圖-地理圍欄功能實現

最近需要實現一個地理圍欄相關的功能。項目是和騎行相關的&#xff0c;主要是當游客或者騎友定位地址進入到對應的景點的地理圍欄里面&#xff0c;則播報景點相關的報道語音。接到需求之后&#xff0c;我開始查看高德的相關API&#xff0c;由于圍欄是多邊形的&#xff0c;則需要…

java abstractrequest,Java AbstractJackson2HttpMessageConverter類代碼示例

import org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter; //導入依賴的package包/類Testpublic void testDefaultConfig() throws Exception {loadBeanDefinitions("mvc-config.xml", 14);RequestMappingHandlerMapping mapping app…

golang調用matlab,Golang中Proto編寫和生成

test.proto文件syntax "proto3";//指定proto文件版本package go; //指定文件縮放的package名//定義對象message Test {enum PhoneType //枚舉消息類型{MOBILE 0; //proto3版本中&#xff0c;首成員必須為0&#xff0c;成員不應有相同的值HOME 1;WORK 2;}int32 fl…

php折半查找面試題,php 面試題(一)

最近轉載一些面試題&#xff0c;希望能給找工作的朋友們帶來一點幫助。1.寫出5個以上你所知道的常用的Linux命令和它的功能cat&#xff0c;顯示文件內容。cd&#xff0c;改變目錄路徑。cp&#xff0c;復制文件。find&#xff0c;查找文件。grep&#xff0c;搜索、過濾信息。ls&…

次梯度法matlab代碼,實例:連續化次梯度法解 LASSO 問題

實例&#xff1a;連續化次梯度法解 LASSO 問題我們將在此頁面中構造一個 LASSO 問題并且展示連續化次梯度方法在其中的應用。目錄構造LASSO優化問題設定隨機種子。clear;seed 97006855;ss RandStream(mt19937ar,Seed,seed);RandStream.setGlobalStream(ss);構造 LASSO 優化問…

php變量使用,php變量的使用

來源:www.cncfan.com | 2006-1-11 | (有1856人讀過)就像大部份的結構化程序&#xff0c;有所謂的全局變量與局部變量&#xff0c;PHP 在這方面也是有相似之處。在 PHP 的程序執行時&#xff0c;系統會在內存中保留一塊全局變量的區域。實際運用時&#xff0c;可以透過 $GLOBALS…

php syncml 協議,基于改進的SyncML協議的圖像安全同步技術研究

Image secure synchronization technology research based on improved SyncML protocolJIA Zhaolong1賈兆攏(1991-)&#xff0c;女&#xff0c;北京郵電大學碩士生&#xff0c;主要研究方向&#xff1a;網絡安全技術與應用MA Zhaofeng2馬兆豐(1974-)&#xff0c;男&#xff0c…

php 文字水印如何居中,php文字水印和php圖片水印實現代碼(二種加水印方法)

$dst_path dst.jpg;$src_path src.jpg;//創建圖片的實例$dst imagecreatefromstring(file_get_contents($dst_path));$src imagecreatefromstring(file_get_contents($src_path));//獲取水印圖片的寬高list($src_w, $src_h) getimagesize($src_path);//將水印圖片復制到目…