背景
你還在寫滿屏的爆炸類嗎?
就是不管三七二十一,把所有代碼寫在一個類里面,這樣代碼不優雅不說,如果改動涉及到老代碼,可能還會影響線上的系統穩定性,
其實,很多情況,我們巧妙地利用設計模式就能解決很多潛在的系統問題,今天堆疊長就教大家使用裝飾器模式,在不改動老代碼的前提下擴展功能,不但能提升代碼優雅性,還能不影響現有的功能,誰用誰知道,真香!!
什么是裝飾器模式?
裝飾器模式,從字面上理解,顧名思義,就是一種裝飾模式,它可以在不改動原有代碼的情況下,對現有的物件、行為進行新的層次的包裝、裝飾,增強原有的基本功能以提供更豐富的能力,
舉個簡單的裝修的小例子:
清理 > 刮膩子 > 涂油漆 > 掛壁畫
也可以是:
清理 > 刮膩子 > 貼大理石 > 掛電視
或者可以是:
清理 > 刮膩子 > 貼墻紙
這是一步步的簡單裝修墻面程序(哈哈,大概如此,我不是專業的),這就是裝飾器模式,裝飾的每個步驟互不干涉,但后面的步驟需要依賴前一個步驟的完成,后面的步驟可以不斷在前一個的裝飾基礎上進行增加,
裝飾器模式結構圖如下:

裝飾器模式類結構如下:
-
Component:組件介面類,定義被裝飾類的基本功能
-
ConcreteComponent: 組件介面的基本實作類
-
Decorator:裝飾器角色類, 實作并持有一個 Component 物件實體
-
ConcreteDecorator:裝飾器的實作類
裝飾器模式的優點:
1、不改動原有代碼,動態增加功能;
2、物件之間不會相互依賴,松耦合,夠優雅;
3、符合開閉原則,擴展性好、便于維護;
裝飾器模式的缺點:
1、裝飾環節如果很多的話,會造成裝飾器類膨脹;
2、裝飾器層層嵌套比較復雜,使用者必須清楚所有的裝飾器類及其用途;
裝飾器模式實戰
我們把上面的裝修的案例用裝飾器模式實作一下,
組件介面類:
/**
* 墻面裝修介面
* @author: 堆疊長
* @from: 公眾號Java技術堆疊
*/
public interface WallBeautify {
/**
* 裝修操作
* @author: 堆疊長
* @from: 公眾號Java技術堆疊
*/
void operation();
}
組件介面的基本實作類:
/**
* 墻面裝修基本實作(清理墻面)
* @author: 堆疊長
* @from: 公眾號Java技術堆疊
*/
public class WallBeautifyClean implements WallBeautify {
@Override
public void operation() {
System.out.println("開始清理墻面");
}
}
裝飾器角色類:
這是一個抽象類,實作并持有一個 Component 物件實體,這里使用的是聚合,而不是繼承,這也是裝飾器模式的要點所在,
/**
* 墻面裝修裝飾器角色
* @author: 堆疊長
* @from: 公眾號Java技術堆疊
*/
public abstract class WallBeautifyDecorator implements WallBeautify {
/**
* 持有一個 Component 物件實體
* @author: 堆疊長
* @from: 公眾號Java技術堆疊
*/
private WallBeautify wallBeautify;
public WallBeautifyDecorator(WallBeautify wallBeautify) {
this.wallBeautify = wallBeautify;
}
@Override
public void operation() {
wallBeautify.operation();
decoration();
}
/**
* 裝飾器實作類自定義實作方法
* @author: 堆疊長
* @from: 公眾號Java技術堆疊
*/
public abstract void decoration();
}
覆寫原操作方法,在原操作之后再進行裝飾,所以需要提供一個抽象的 decoration 方法供不同的裝飾器的實作類去實作,
裝飾器的實作類:
這里定義了 3 個裝修程序:
刮膩子 > 涂油漆 > 掛壁畫
所以各自去繼承 裝飾器角色類 并實作其裝飾方法:
/**
* 墻面裝修裝飾器角色實作(刮膩子)
* @author: 堆疊長
* @from: 公眾號Java技術堆疊
*/
public class WallBeautifyPutty extends WallBeautifyDecorator {
public WallBeautifyPutty(WallBeautify wallBeautify) {
super(wallBeautify);
}
@Override
public void decoration() {
System.out.println("開始刮膩子");
}
}
/**
* 墻面裝修裝飾器角色實作(涂油漆)
* @author: 堆疊長
* @from: 公眾號Java技術堆疊
*/
public class WallBeautifyPaint extends WallBeautifyDecorator {
public WallBeautifyPaint(WallBeautify wallBeautify) {
super(wallBeautify);
}
@Override
public void decoration() {
System.out.println("開始涂油漆");
}
}
/**
* 墻面裝修裝飾器角色實作(掛壁畫)
* @author: 堆疊長
* @from: 公眾號Java技術堆疊
*/
public class WallBeautifyHang extends WallBeautifyDecorator {
public WallBeautifyHang(WallBeautify wallBeautify) {
super(wallBeautify);
}
@Override
public void decoration() {
System.out.println("開始掛壁畫");
}
}
測驗一下:
/**
* 裝飾器模式測驗類
* @author: 堆疊長
* @from: 公眾號Java技術堆疊
*/
public class DecoratorTest {
public static void main(String[] args) {
// 清理墻面
WallBeautify wallBeautifyClean = new WallBeautifyClean();
wallBeautifyClean.operation();
System.out.println("--------------");
// 刮膩子
WallBeautify wallBeautifyPutty = new WallBeautifyPutty(wallBeautifyClean);
wallBeautifyPutty.operation();
System.out.println("--------------");
// 涂油漆
WallBeautify wallBeautifyPaint = new WallBeautifyPaint(wallBeautifyPutty);
wallBeautifyPaint.operation();
System.out.println("--------------");
// 掛壁畫
WallBeautify wallBeautifyHang = new WallBeautifyHang(wallBeautifyPaint);
wallBeautifyHang.operation();
System.out.println("--------------");
// 多層嵌套
WallBeautify wbh = new WallBeautifyHang(new WallBeautifyPaint(
new WallBeautifyPutty(new WallBeautifyClean())));
wbh.operation();
System.out.println("--------------");
}
}
本節教程所有實戰原始碼已上傳到這個倉庫:
https://github.com/javastacks/javastack
輸出結果:
開始清理墻面
--------------
開始清理墻面
開始刮膩子
--------------
開始清理墻面
開始刮膩子
開始涂油漆
--------------
開始清理墻面
開始刮膩子
開始涂油漆
開始掛壁畫
--------------
開始清理墻面
開始刮膩子
開始涂油漆
開始掛壁畫
--------------
結果輸出正常!
可以看到,裝飾器模式的使用還是相對比較簡單的,使用裝飾器模式可以達到不同的裝飾效果,這樣即滿足了不同客戶的需求,而又不用改動原有的代碼,還是挺香的,
后續《設計模式》系列文章在公眾號Java技術堆疊陸續更新中,請大家持續關注哦!
裝飾器模式在 JDK 中的應用
現在我們知道如何使用裝飾器模式了,現在我們再看看 JDK 哪些地方運用了裝飾器模式呢,
1、IO 流
最經典的裝飾器模式應用莫過于 JDK 中的 IO 流了(InputStream/ OutputStream)
常用的 InputStream 類結構類如下:

InputStream 和 FileInputStream 是基本的組件介面和實作,
FilterInputStream 就是一個實作組件介面并持有實體參考的裝飾器角色:

BufferedInputStream、DataInputStream 都是不同的 FilterInputStream 的裝飾實作,
OutputStream 也是同樣的原理,
2、同步集合
要對非執行緒安全的集合(如:List、Set)簡單提供執行緒安全的功能,使用裝飾器模式也能輕松實作,
來看同步集合工具類方法:
java.util.Collections#synchronizedList(List)
java.util.Collections#synchronizedSet(Set)

它們都是 SynchronizedCollection 的裝飾器實作類:

SynchronizedCollection 是裝飾器角色:

SynchronizedCollection 實作了集合組件介面并持有集合實體參考,而 Collection(List) 和 ArrayList 是基本的組件介面和實作,
總結
本文介紹了裝飾器模式的基本概念,也做了一個基本實戰,并且舉了兩個 JDK 中的裝飾器模式的例子,相信大家對裝飾器模式有了一個基本認識了,怎么運用到專案中,大家應該有譜了吧?
當然,設計模式只是給大家一個設計的參考,并不能盲目運用,否則適得其反,話說,你是怎么在專案中應用裝飾器模式的呢?歡迎留言分享案例!
本節教程所有實戰原始碼已上傳到這個倉庫:
https://github.com/javastacks/javastack
好了,今天的分享就到這里了,后面堆疊長我會更新其他設計模式的實戰文章,公眾號Java技術堆疊第一時間推送,Java技術堆疊《設計模式》系列文章陸續更新中,請大家持續關注哦!
最后,覺得我的文章對你用識訓的話,動動小手,給個在看、轉發,原創不易,堆疊長需要你的鼓勵,
著作權宣告: 本文系公眾號 "Java技術堆疊" 原創,轉載、參考本文內容請注明出處,抄襲、洗稿一律投訴侵權,后果自負,并保留追究其法律責任的權利,
近期熱文推薦:
1.1,000+ 道 Java面試題及答案整理(2022最新版)
2.勁爆!Java 協程要來了,,,
3.Spring Boot 2.x 教程,太全了!
4.20w 程式員紅包封面,快快領取,,,
5.《Java開發手冊(嵩山版)》最新發布,速速下載!
覺得不錯,別忘了隨手點贊+轉發哦!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/434370.html
標籤:Java
