国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

目錄
裝飾模式UML圖 " >裝飾模式UML圖
裝飾器模式中的角色 " >裝飾器模式中的角色
小結(jié)" >小結(jié)
實(shí)戰(zhàn) " >實(shí)戰(zhàn)
大神們是怎么用的 " >大神們是怎么用的
JDK源碼中" >JDK源碼中
Spring源碼中" >Spring源碼中
Mybatis源碼中" >Mybatis源碼中
首頁 Java java教程 3年工作必備 裝飾器模式

3年工作必備 裝飾器模式

Aug 28, 2023 pm 03:09 PM
裝飾器模式


好啦,進(jìn)入我們的主題,今天我給大家分享設(shè)計(jì)模式中的裝飾器模式。用貼切的生活故事,以及真實(shí)項(xiàng)目場景來講設(shè)計(jì)模式,最后用一句話來總結(jié)這個(gè)設(shè)計(jì)模式。

故事

古話說的好:人靠衣裳馬靠鞍。下面先帶大家來熟悉這句話的背景:

人靠衣裝馬靠鞍,狗配鈴鐺跑的歡出自沈自晉《望湖亭記》第十出:“雖然如此,佛靠金裝,人靠衣裝,打扮也是很要緊的?!薄缎咽篮阊浴肪硪?兩縣令競義婚孤女:”常言道:’佛是金裝,人是衣裝,世人眼孔淺的多,只有皮相,沒有骨相?!彼渍Z我們會(huì)說成人靠衣裝馬靠鞍。

這個(gè)經(jīng)典故事,讓我想起了一個(gè)設(shè)計(jì)模式:裝飾器模式。

什么是裝飾器模式呢?請(qǐng)聽老田慢慢道來。

裝飾器模式概述

裝飾器模式(Decorator Pattern)也叫作包裝器模式(Wrapper Pattern),指在不改變?cè)袑?duì)象的基礎(chǔ)上,動(dòng)態(tài)地給一個(gè)對(duì)象添加一些額外的職責(zé)。就增加功能來說,裝飾器模式相比生成子類更為靈活,屬于結(jié)構(gòu)型設(shè)計(jì)模式。

英文:

Attach additional responsibilities to an object dynamicallykeeping the same interface.Decorators provide a flexible alternativeto subclassing for extending functionality.

.擴(kuò)充原有物件的功能)將功能附加到物件上。因此,裝飾器模式的核心是功能擴(kuò)充。使用裝飾器模式可以透明且動(dòng)態(tài)地?cái)U(kuò)展類別的功能。

生活中的案例

#一套毛坯房,沒有裝修之前,看起來非常難看,但只要稍微裝潢一番,那就漂亮多了,而且能洗澡、睡覺、做飯等,但本質(zhì)還是房子。

一輛汽車,原本就是一輛代步的車,但是瑪麗加大,配置提升,然後就成了豪車,但本質(zhì)還是一輛代步的車。

一個(gè)女生,原本很平凡,長相一般,但是經(jīng)過一番化妝,再穿點(diǎn)好看的衣服,然後就成了很多人心中的女神了。

總之,經(jīng)過點(diǎn)裝飾後,就是不一樣了,功能增強(qiáng)了。

裝飾器模式通用程式碼實(shí)作

#我們還是用程式碼來實(shí)現(xiàn)一把,程式設(shè)計(jì)師都喜歡先搞個(gè)demo,然後再慢慢研究。

//抽象組件
public abstract class Component {
    public abstract void operation();
}
//具體組件
public class ConcreteComponent extends Component {
    @Override
    public void operation() {
        System.out.println("ConcreteComponent operation");
    }
}
//裝飾器抽象
public abstract class Decorator extends Component {

    protected Component component;

    public Decorator(Component component) {
        this.component = component;
    }

    @Override
    public void operation() {
        component.operation();
    }
}
//具體裝飾器
public class ConcreteDecorator extends Decorator {
    public ConcreteDecorator(Component component) {
        super(component);
    }

    @Override
    public void operation() {
        System.out.println("開始前搞點(diǎn)事");
        super.operation();
        System.out.println("結(jié)束后搞點(diǎn)事");
    }
}
//測試
public class Client {
    public static void main(String[] args) {
        Component component = new ConcreteDecorator(new ConcreteComponent());
        component.operation();
    }
}

運(yùn)行結(jié)果:

開始前搞點(diǎn)事
ConcreteComponent operation
結(jié)束后搞點(diǎn)事

以上便是裝飾器模式的通用程式碼實(shí)現(xiàn),下面我們來分析一下。

裝飾模式UML圖

3年工作必備 裝飾器模式


#從UML途中可以看出,其中的角色

裝飾器模式中的角色

  • 抽象組件(Component):可以是一個(gè)接口或者抽象類,充當(dāng)被裝飾類的原始對(duì)象,規(guī)定了被裝飾對(duì)象的行為。
  • 具體組件(ConcreteComponent):實(shí)現(xiàn)/繼承Component的一個(gè)具體對(duì)象,即被裝飾對(duì)象。
  • 抽象裝飾器(Decorator):通用的裝飾ConcreteComponent的裝飾器,其內(nèi)部必然有一個(gè)屬性指向Component;其實(shí)現(xiàn)一般是一個(gè)抽象類,主要為了讓其子類按照其構(gòu)造形式傳入一個(gè)Component,這是強(qiáng)制的通用行為。如果系統(tǒng)中裝飾邏輯單一,則并不需要實(shí)現(xiàn)許多裝飾器,可以直接省略該類,而直接實(shí)現(xiàn)一個(gè)具體裝飾器即可。
  • 具體裝飾器(ConcreteDecorator):Decorator的具體實(shí)現(xiàn)類,理論上,每個(gè)ConcreteDecorator都擴(kuò)展了Component對(duì)象的一種功能。

小結(jié)

裝飾器模式角色分配符合設(shè)計(jì)模式的里氏替換原則、依賴倒置原則,從而使得其具備很強(qiáng)的擴(kuò)展性,最終滿足開閉原則。

裝飾器模式的實(shí)現(xiàn)原理是,讓裝飾器實(shí)現(xiàn)與被裝飾類(例如ConcreteComponent)相同的接口(例如Component),使得裝飾器與被擴(kuò)展類類型一致,并在構(gòu)造函數(shù)中傳入該接口對(duì)象,然后在實(shí)現(xiàn)這個(gè)接口的被包裝類對(duì)象的現(xiàn)有功能上添加新功能。由于裝飾器與被包裝類屬于同一類型(均為Component),且構(gòu)造函數(shù)的參數(shù)為其實(shí)現(xiàn)接口類(Component),因此裝飾器模式具備嵌套擴(kuò)展功能,這樣就能使用裝飾器模式一層一層地對(duì)底層被包裝類進(jìn)行功能擴(kuò)展了。

實(shí)戰(zhàn)

在實(shí)際開發(fā)中,都會(huì)存在系統(tǒng)與系統(tǒng)之間的調(diào)用,假如說我們現(xiàn)在有個(gè)支付功能,現(xiàn)在一切都是沒問題的,但是 我們此時(shí)需要對(duì)發(fā)起支付前的請(qǐng)求參數(shù)和支付后的相應(yīng)參數(shù)。進(jìn)行統(tǒng)一處理,原功能不變,只是在原功能上做了一點(diǎn)擴(kuò)展(增強(qiáng))。

老功能代碼如下:

/**
 * @author 田先生
 * @date 2021-06-02
 *
 * 歡迎關(guān)注公眾號(hào):java后端技術(shù)全棧
 */
public interface IOrderPayService {
    String payment(Long orderId, BigDecimal amount);
}
public class OrderPayServiceImpl implements IOrderPayService {

    @Override
    public String payment(Long orderId, BigDecimal amount) {
        //先調(diào)用余額查詢是否足夠
        System.out.println("發(fā)起支付,訂單號(hào):" + orderId + ", 支付金額:" + amount.toString());
        //調(diào)用支付系統(tǒng)
        String result = "訂單id=" + orderId + "支付完成";
        System.out.println("支付結(jié)果:" + result);
        return result;
    }
}
public class OrderClient {
    public static void main(String[] args) {
        IOrderPayService orderPayService = new OrderPayServiceImpl();
        orderPayService.payment(10001L,new BigDecimal("5000"));
    }
}

運(yùn)行輸出:

發(fā)起支付,訂單號(hào):10001, 支付金額:5000
支付結(jié)果:訂單id=10001支付完成

新需求,需要把這些請(qǐng)求參數(shù)和相應(yīng)結(jié)果進(jìn)行單獨(dú)搜集處理,此時(shí)為了不影響原有功能,于是我們可以對(duì)其進(jìn)行功能增強(qiáng)。

/**
 * @author 田先生
 * @date 2021-06-02
 *
 * 歡迎關(guān)注公眾號(hào):java后端技術(shù)全棧
 */
public class OrderPayDecorator implements IOrderPayService {

    private IOrderPayService orderPayService;

    public OrderPayDecorator(IOrderPayService orderPayService) {
        this.orderPayService = orderPayService;
    }

    @Override
    public String payment(Long orderId, BigDecimal amount) {
        System.out.println("把這個(gè)訂單信息(發(fā)起支付)" + "訂單id=" + orderId + "支付金額=" + amount.toString() + " 【發(fā)送給MQ】");
        String result = orderPayService.payment(orderId, amount);
        System.out.println("把訂單支付結(jié)果信息" + result + " 【發(fā)送給MQ】");
        return result;
    }
}
public class OrderClient {
    public static void main(String[] args) {
        IOrderPayService orderPayService =new OrderPayDecorator(new OrderPayServiceImpl());
        orderPayService.payment(10001L,new BigDecimal("5000"));
    }
}

運(yùn)行輸出:

把這個(gè)訂單信息(發(fā)起支付)訂單id=10001支付金額=5000 【發(fā)送給MQ】
發(fā)起支付,訂單號(hào):10001, 支付金額:5000
支付結(jié)果:訂單id=10001支付完成
把訂單支付結(jié)果信息訂單id=10001支付完成 【發(fā)送給MQ】

整個(gè)過程,大家有沒有發(fā)現(xiàn),我們并沒動(dòng)原有的代碼,僅僅只是做了功能增強(qiáng)。

裝飾器模式在新項(xiàng)目中基本上不會(huì)用到,通常都是在老項(xiàng)目中使用,因?yàn)橐延械墓δ懿蛔?,只是做了一些功能增?qiáng)。

大神們是怎么用的

裝飾器設(shè)計(jì)模式在JDK源碼、Spring源碼以及Mybatis源碼中都有。

JDK源碼中

裝飾器模式比較經(jīng)典的應(yīng)用就是 JDK 中的 java.io 包下,InputStream、OuputStream、Reader、Writer 及它們的子類。

以 InputStream 為例

  • FileInputStream 是 InputStream 的子類,用來讀取文件字節(jié)流
  • BufferedInputStream 是 InputStream 的子類的子類,可緩存的字節(jié)流
  • DataInputStream 也是 InputStream 的子類的子類,可直接讀取 Java 基本類型的字節(jié)流

UML圖

3年工作必備 裝飾器模式


DataInputStream 中構(gòu)造器入?yún)⒈闶亲约旱母割悾↖nputStream)。

3年工作必備 裝飾器模式

如果希望提供一個(gè)可以讀取文件 + 可緩存的字節(jié)流,使用繼承方式,就需要派生 FileBufferedInputStream;

如果希望提供一個(gè)可以讀取文件 + 直接讀取基本類型的字節(jié)流,使用繼承方式,就需要派生 FileDataInputStream。

字節(jié)流功能的增強(qiáng)還包括支持管道 pipe、字節(jié)數(shù)組 bytearray、字節(jié)對(duì)象 object、字節(jié)流字符流的轉(zhuǎn)換 等維度,如果用繼承方式,那類的層級(jí)與種類會(huì)多到爆炸。

為了解決問題,這邊就使用了裝飾器模式。

Spring源碼中

在Spring中,我們可以嘗試?yán)斫庖幌耇ransactionAwareCacheDecorator類,這個(gè)類主要用來處理事務(wù)緩存,代碼如下。

public class TransactionAwareCacheDecorator implements Cache {
    private final Cache targetCache;
    //構(gòu)造方法入?yún)㈩愋蜑樽约旱母割悾ń涌陬愋停?    public TransactionAwareCacheDecorator(Cache targetCache) {
        Assert.notNull(targetCache, "Target Cache must not be null");
        this.targetCache = targetCache;
    }

    public Cache getTargetCache() {
        return this.targetCache;
    }
    //...
}

TransactionAwareCacheDecorator就是對(duì)Cache的一個(gè)包裝,因此,這里也是使用了裝飾器模式。

Mybatis源碼中

MyBatis中關(guān)于Cache和CachingExecutor接口的實(shí)現(xiàn)類也使用了裝飾者設(shè)計(jì)模式。Executor是MyBatis執(zhí)行器,是MyBatis 調(diào)度的核心,負(fù)責(zé)SQL語句的生成和查詢緩存的維護(hù);CachingExecutor是一個(gè)Executor的裝飾器,給一個(gè)Executor增加了緩存的功能。此時(shí)可以看做是對(duì)Executor類的一個(gè)增強(qiáng),故使用裝飾器模式是合適的。

在CachingExecutor 中

public class CachingExecutor implements Executor {
  //持有組件對(duì)象
  private Executor delegate;
  private TransactionalCacheManager tcm = new TransactionalCacheManager();
    //構(gòu)造方法,傳入組件對(duì)象
  public CachingExecutor(Executor delegate) {
    this.delegate = delegate;
    delegate.setExecutorWrapper(this);
  }
  @Override
  public int update(MappedStatement ms, Object parameterObject) throws SQLException {
      //轉(zhuǎn)發(fā)請(qǐng)求給組件對(duì)象,可以在轉(zhuǎn)發(fā)前后執(zhí)行一些附加動(dòng)作
    flushCacheIfRequired(ms);
    return delegate.update(ms, parameterObject);
  }
  //...
 }

總結(jié)

看完裝飾器模式后,你是否有感覺,裝飾器模式和代理模式非常的相像,下面我們就來做個(gè)對(duì)比。

1.裝飾器模式可以理解為一種特殊的代理模式。

2.裝飾器模式強(qiáng)調(diào)自身的功能擴(kuò)展,透明的擴(kuò)展(即用戶想增強(qiáng)什么功能就增強(qiáng)什么功能),可動(dòng)態(tài)定制的擴(kuò)展。

3.代理模式強(qiáng)調(diào)的是代理過程的控制。

優(yōu)點(diǎn)

  • 裝飾器是繼承的有力補(bǔ)充,比繼承靈活,在不改變?cè)袑?duì)象的情況下,動(dòng)態(tài)地給一個(gè)對(duì)象擴(kuò)展功能,即插即用。
  • 通過使用不同裝飾類及這些裝飾類的排列組合,可以實(shí)現(xiàn)不同效果。
  • 裝飾器模式完全遵守開閉原則。

缺點(diǎn)

  • 會(huì)出現(xiàn)更多的代碼、更多的類,增加程序的復(fù)雜性。
  • 動(dòng)態(tài)裝飾在多層裝飾時(shí)會(huì)更復(fù)雜。

以上是3年工作必備 裝飾器模式的詳細(xì)內(nèi)容。更多資訊請(qǐng)關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

本網(wǎng)站聲明
本文內(nèi)容由網(wǎng)友自願(yuàn)投稿,版權(quán)歸原作者所有。本站不承擔(dān)相應(yīng)的法律責(zé)任。如發(fā)現(xiàn)涉嫌抄襲或侵權(quán)的內(nèi)容,請(qǐng)聯(lián)絡(luò)admin@php.cn

熱AI工具

Undress AI Tool

Undress AI Tool

免費(fèi)脫衣圖片

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅(qū)動(dòng)的應(yīng)用程序,用於創(chuàng)建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費(fèi)的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費(fèi)的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強(qiáng)大的PHP整合開發(fā)環(huán)境

Dreamweaver CS6

Dreamweaver CS6

視覺化網(wǎng)頁開發(fā)工具

SublimeText3 Mac版

SublimeText3 Mac版

神級(jí)程式碼編輯軟體(SublimeText3)

hashmap和hashtable之間的區(qū)別? hashmap和hashtable之間的區(qū)別? Jun 24, 2025 pm 09:41 PM

HashMap與Hashtable的區(qū)別主要體現(xiàn)在線程安全、null值支持及性能方面。 1.線程安全方面,Hashtable是線程安全的,其方法大多為同步方法,而HashMap不做同步處理,非線程安全;2.null值支持上,HashMap允許一個(gè)null鍵和多個(gè)null值,Hashtable則不允許null鍵或值,否則拋出NullPointerException;3.性能方面,HashMap因無同步機(jī)制效率更高,Hashtable因每次操作加鎖性能較低,推薦使用ConcurrentHashMap替

為什麼我們需要包裝紙課? 為什麼我們需要包裝紙課? Jun 28, 2025 am 01:01 AM

Java使用包裝類是因?yàn)榛緮?shù)據(jù)類型無法直接參與面向?qū)ο癫僮?,而?shí)際需求中常需對(duì)象形式;1.集合類只能存儲(chǔ)對(duì)象,如List利用自動(dòng)裝箱存儲(chǔ)數(shù)值;2.泛型不支持基本類型,必須使用包裝類作為類型參數(shù);3.包裝類可表示null值,用於區(qū)分未設(shè)置或缺失的數(shù)據(jù);4.包裝類提供字符串轉(zhuǎn)換等實(shí)用方法,便於數(shù)據(jù)解析與處理,因此在需要這些特性的場景下,包裝類不可或缺。

什麼是接口中的靜態(tài)方法? 什麼是接口中的靜態(tài)方法? Jun 24, 2025 pm 10:57 PM

StaticmethodsininterfaceswereintroducedinJava8toallowutilityfunctionswithintheinterfaceitself.BeforeJava8,suchfunctionsrequiredseparatehelperclasses,leadingtodisorganizedcode.Now,staticmethodsprovidethreekeybenefits:1)theyenableutilitymethodsdirectly

JIT編譯器如何優(yōu)化代碼? JIT編譯器如何優(yōu)化代碼? Jun 24, 2025 pm 10:45 PM

JIT編譯器通過方法內(nèi)聯(lián)、熱點(diǎn)檢測與編譯、類型推測與去虛擬化、冗餘操作消除四種方式優(yōu)化代碼。 1.方法內(nèi)聯(lián)減少調(diào)用開銷,將頻繁調(diào)用的小方法直接插入調(diào)用處;2.熱點(diǎn)檢測識(shí)別高頻執(zhí)行代碼並集中優(yōu)化,節(jié)省資源;3.類型推測收集運(yùn)行時(shí)類型信息實(shí)現(xiàn)去虛擬化調(diào)用,提升效率;4.冗餘操作消除根據(jù)運(yùn)行數(shù)據(jù)刪除無用計(jì)算和檢查,增強(qiáng)性能。

什麼是實(shí)例初始器塊? 什麼是實(shí)例初始器塊? Jun 25, 2025 pm 12:21 PM

實(shí)例初始化塊在Java中用於在創(chuàng)建對(duì)象時(shí)運(yùn)行初始化邏輯,其執(zhí)行先於構(gòu)造函數(shù)。它適用於多個(gè)構(gòu)造函數(shù)共享初始化代碼、複雜字段初始化或匿名類初始化場景,與靜態(tài)初始化塊不同的是它每次實(shí)例化時(shí)都會(huì)執(zhí)行,而靜態(tài)初始化塊僅在類加載時(shí)運(yùn)行一次。

變量的最終關(guān)鍵字是什麼? 變量的最終關(guān)鍵字是什麼? Jun 24, 2025 pm 07:29 PM

InJava,thefinalkeywordpreventsavariable’svaluefrombeingchangedafterassignment,butitsbehaviordiffersforprimitivesandobjectreferences.Forprimitivevariables,finalmakesthevalueconstant,asinfinalintMAX_SPEED=100;wherereassignmentcausesanerror.Forobjectref

什麼是工廠模式? 什麼是工廠模式? Jun 24, 2025 pm 11:29 PM

工廠模式用於封裝對(duì)象創(chuàng)建邏輯,使代碼更靈活、易維護(hù)、松耦合。其核心答案是:通過集中管理對(duì)象創(chuàng)建邏輯,隱藏實(shí)現(xiàn)細(xì)節(jié),支持多種相關(guān)對(duì)象的創(chuàng)建。具體描述如下:工廠模式將對(duì)象創(chuàng)建交給專門的工廠類或方法處理,避免直接使用newClass();適用於多類型相關(guān)對(duì)象創(chuàng)建、創(chuàng)建邏輯可能變化、需隱藏實(shí)現(xiàn)細(xì)節(jié)的場景;例如支付處理器中通過工廠統(tǒng)一創(chuàng)建Stripe、PayPal等實(shí)例;其實(shí)現(xiàn)包括工廠類根據(jù)輸入?yún)?shù)決定返回的對(duì)象,所有對(duì)象實(shí)現(xiàn)共同接口;常見變體有簡單工廠、工廠方法和抽象工廠,分別適用於不同複雜度的需求。

什麼是類型鑄造? 什麼是類型鑄造? Jun 24, 2025 pm 11:09 PM

類型轉(zhuǎn)換有兩種:隱式和顯式。 1.隱式轉(zhuǎn)換自動(dòng)發(fā)生,如將int轉(zhuǎn)為double;2.顯式轉(zhuǎn)換需手動(dòng)操作,如使用(int)myDouble。需要類型轉(zhuǎn)換的情況包括處理用戶輸入、數(shù)學(xué)運(yùn)算或函數(shù)間傳遞不同類型的值時(shí)。需要注意的問題有:浮點(diǎn)數(shù)轉(zhuǎn)整數(shù)會(huì)截?cái)嘈?shù)部分、大類型轉(zhuǎn)小類型可能導(dǎo)致數(shù)據(jù)丟失、某些語言不允許直接轉(zhuǎn)換特定類型。正確理解語言的轉(zhuǎn)換規(guī)則有助於避免錯(cuò)誤。

See all articles