只有光頭才能變強數據庫
回顧前面:設計模式
前一篇已經講解了代理模式了,今天要講解的就是裝飾模式啦~微信
在看到FilterInputStream
和FilterOutputStream
時看到了以前常聽見的裝飾模式(對IO必定了解的同窗可能都會知道那麼一句話:在IO用得最多的就是裝飾模式了)!ide
其實不管是代理模式仍是裝飾模式。本質上我認爲就是對原有對象加強的方式~函數
那麼接下來就開始吧,若是文章有錯誤的地方請你們多多包涵,不吝在評論區指正哦~post
聲明:本文使用JDK1.8this
不少時候咱們可能對Java提供給咱們的對象不滿意,不能知足咱們的功能。此時咱們就想對Java原對象進行加強,可以實現咱們想要的功能就好~spa
通常來講,實現對象加強有三種方式:設計
最簡單的方式就是繼承父類,子類擴展來達到目的。雖然簡單,可是這種方式的缺陷很是大:代理
第一點就拿之前在學JDBC的時候來講:
List<Connection>
來管理。顯然咱們的對象是Connection,當寫到close()
方法的時候卡住了。close()
是讓咱們的Connection返回到「鏈接池」(集合)中,而不是關閉掉。close()
方法了。第二點我也舉個例子:
如今我設計一個電話類:
public class Phone { // 能夠打電話 public void call() { System.out.println("打電話給周圍的人關注公衆號Java3y"); } }
此時,我想打電話以前能聽彩鈴,因而我繼承Phone類,實現我想要的功能。
public class MusicPhone extends Phone { // 聽彩鈴 public void listenMusic() { System.out.println("我懷念的是無話不說,我懷念的是一塊兒作夢~~~~~~"); } @Override public void call() { // 在打電話以前聽彩鈴 listenMusic(); super.call(); } }
咱們的功能就作好了:
// 這裏繼承的是MusicPhone類 public class GiveCurrentTimePhone extends MusicPhone { // 給出當前的時間 public void currentTime() { System.out.println("當前的時間是:" + System.currentTimeMillis()); } @Override public void call() { super.call(); // 打完電話提示如今的時間是多少啦 currentTime(); } }
因此咱們仍是能夠完成任務滴:
但是我需求如今又想變了:
因此,咱們能夠看到子類繼承父類這種方式來擴展是十分侷限的,不靈活的~
所以咱們就有了裝飾模式!
首先咱們來看看裝飾模式是怎麼用的吧。
電話接口:
// 一個良好的設計是抽取成接口或者抽象類的 public interface Phone { // 能夠打電話 void call(); }
具體的實現:
public class IphoneX implements Phone { @Override public void call() { System.out.println("打電話給周圍的人關注公衆號Java3y"); } }
上面咱們已經擁有了一個接口還有一個默認實現。包裝模式是這樣乾的:
首先咱們弄一個裝飾器,它實現了接口,以組合的方式接收咱們的默認實現類。
// 裝飾器,實現接口 public abstract class PhoneDecorate implements Phone { // 以組合的方式來獲取默認實現類 private Phone phone; public PhoneDecorate(Phone phone) { this.phone = phone; } @Override public void call() { phone.call(); } }
有了裝飾器之後,咱們的擴展均可以以裝飾器爲基礎進行擴展,繼承裝飾器來擴展就行了!
咱們想要在打電話以前聽音樂:
// 繼承着裝飾器來擴展 public class MusicPhone extends PhoneDecorate { public MusicPhone(Phone phone) { super(phone); } // 定義想要擴展的功能 public void listenMusic() { System.out.println("繼續跑 帶着赤子的驕傲,生命的閃耀不堅持到底怎能看到,與其苟延殘喘不如縱情燃燒"); } // 重寫打電話的方法 @Override public void call() { // 在打電話以前聽音樂 listenMusic(); super.call(); } }
如今我也想在打完電話後通知當前的時間,因而咱們也繼承裝飾類來擴展:
// 這裏繼承的是MusicPhone裝飾器類 public class GiveCurrentTimePhone extends PhoneDecorate { public GiveCurrentTimePhone(Phone phone) { super(phone); } // 自定義想要實現的功能:給出當前的時間 public void currentTime() { System.out.println("當前的時間是:" + System.currentTimeMillis()); } // 重寫要加強的方法 @Override public void call() { super.call(); // 打完電話後通知一下當前時間 currentTime(); } }
能夠完成任務:
就目前這樣看起來,比我直接繼承父類要麻煩,而功能效果是同樣的....咱們繼續往下看~~
此時,我不想在打電話以前聽到彩鈴了,很簡單:咱們不裝飾它就行了!
此時,我想在打電話前報告一下時間,在打完電話以後聽彩鈴。
GiveCurrentTimePhone類
和MusicPhone類
自己從語義上就沒有規定擴展功能的執行順序
因此咱們仍是能夠很簡單地完成功能:
可能有的同窗在看完上面的代碼以後,仍是迷迷糊糊地不知道裝飾模式是怎麼實現「裝飾」的。下面我就再來解析一下:
再來看看下面的圖,就懂了!
每每咱們的代碼能夠省略起來,成了這個樣子(是否是和IO的很是像!)
// 先加強聽音樂的功能,再加強通知時間的功能 Phone phone = new GiveCurrentTimePhone(new MusicPhone(new IphoneX()));
結果是同樣的:
優勢:
缺點:
最後來補充一下包裝模式和代理模式的類圖:
對象加強的三種方式:
那麼只要遇到Java提供給咱們的API不夠用,咱們加強一下就好了。在寫代碼時,某個類被寫死了,功能不夠用,加強一下就能夠了!
理解包裝模式,接下來就開始IO之旅咯~~~
參考資料:
若是文章有錯的地方歡迎指正,你們互相交流。習慣在微信看技術文章,想要獲取更多的Java資源的同窗,能夠關注微信公衆號:Java3y。
文章的目錄導航: