成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

包裝模式就是這么簡單啦

Developer / 3522人閱讀

摘要:包裝模式是這樣干的首先我們弄一個(gè)裝飾器,它實(shí)現(xiàn)了接口,以組合的方式接收我們的默認(rèn)實(shí)現(xiàn)類。其實(shí)裝飾器抽象類的作用就是代理核心的功能還是由最簡單的實(shí)現(xiàn)類來做,只不過在擴(kuò)展的時(shí)候可以添加一些沒有的功能而已。

前言
只有光頭才能變強(qiáng)

回顧前面:

給女朋友講解什么是代理模式

前一篇已經(jīng)講解了代理模式了,今天要講解的就是裝飾模式啦~

在看到FilterInputStreamFilterOutputStream時(shí)看到了之前常聽見的裝飾模式(對(duì)IO一定了解的同學(xué)可能都會(huì)知道那么一句話:在IO用得最多的就是裝飾模式了)!

其實(shí)無論是代理模式還是裝飾模式。本質(zhì)上我認(rèn)為就是對(duì)原有對(duì)象增強(qiáng)的方式~

那么接下來就開始吧,如果文章有錯(cuò)誤的地方請(qǐng)大家多多包涵,不吝在評(píng)論區(qū)指正哦~

聲明:本文使用JDK1.8
一、對(duì)象增強(qiáng)的常用方式

很多時(shí)候我們可能對(duì)Java提供給我們的對(duì)象不滿意,不能滿足我們的功能。此時(shí)我們就想對(duì)Java原對(duì)象進(jìn)行增強(qiáng),能夠?qū)崿F(xiàn)我們想要的功能就好~

一般來說,實(shí)現(xiàn)對(duì)象增強(qiáng)有三種方式:

繼承

繼承父類,子類擴(kuò)展

裝飾器模式

使用“包裝”的方式來增強(qiáng)對(duì)象

代理模式

給女朋友講解么是代理模式

1.1繼承

最簡單的方式就是繼承父類,子類擴(kuò)展來達(dá)到目的。雖然簡單,但是這種方式的缺陷非常大

一、如果父類是帶有數(shù)據(jù)、信息、屬性的話,那么子類無法增強(qiáng)。

二、子類實(shí)現(xiàn)了之后需求無法變更,增強(qiáng)的內(nèi)容是固定的。

1.1.1第一點(diǎn)

第一點(diǎn)就拿以前在學(xué)JDBC的時(shí)候來說:

當(dāng)時(shí)想要自己寫一個(gè)簡易的JDBC連接池,連接池由List來管理。顯然我們的對(duì)象是Connection,當(dāng)寫到close()方法的時(shí)候卡住了。

因?yàn)槲覀兿胍墓δ苁牵赫{(diào)用close()是讓我們的Connection返回到“連接池”(集合)中,而不是關(guān)閉掉。

此時(shí)我們不能使用繼承父類的方式來實(shí)現(xiàn)增強(qiáng)。因?yàn)镃onnection對(duì)象是由數(shù)據(jù)庫廠商來實(shí)現(xiàn)的,在得到Connection對(duì)象的時(shí)候綁定了各種信息(數(shù)據(jù)庫的username、password、具體的數(shù)據(jù)庫是啥等等)。我們子類繼承Connection是無法得到對(duì)應(yīng)的數(shù)據(jù)的!就更別說調(diào)用close()方法了。

1.1.2第二點(diǎn)

第二點(diǎn)我也舉個(gè)例子:

現(xiàn)在我設(shè)計(jì)一個(gè)電話類:

public class Phone {
    // 可以打電話
    public void call() {
        System.out.println("打電話給周圍的人關(guān)注公眾號(hào)Java3y");
    }
}

此時(shí),我想打電話之前能聽彩鈴,于是我繼承Phone類,實(shí)現(xiàn)我想要的功能。

public class MusicPhone extends Phone {
    
    // 聽彩鈴
    public void listenMusic() {
        System.out.println("我懷念的是無話不說,我懷念的是一起做夢(mèng)~~~~~~");
    }

    @Override
    public void call() {

        // 在打電話之前聽彩鈴
        listenMusic();

        super.call();
    }
}

我們的功能就做好了:

此時(shí),我又突然想實(shí)現(xiàn)多一個(gè)需求了,我想要聽完電話之后告訴我一下當(dāng)前的時(shí)間是多少。沒事,我們又繼承來增強(qiáng)一下:

// 這里繼承的是MusicPhone類
public class GiveCurrentTimePhone extends MusicPhone {

    // 給出當(dāng)前的時(shí)間
    public void currentTime() {
        System.out.println("當(dāng)前的時(shí)間是:" + System.currentTimeMillis());
    }

    @Override
    public void call() {
        super.call();

        // 打完電話提示現(xiàn)在的時(shí)間是多少啦
        currentTime();
    }
}

所以我們還是可以完成任務(wù)滴:

可是我需求現(xiàn)在又想變了:

我不想聽彩鈴了,只想聽完電話通知一下時(shí)間就好了........(可是我們的通知時(shí)間電話類是繼承在聽彩鈴的電話類基礎(chǔ)之上的),,,

我又有可能:我想在聽電話之前報(bào)告一下時(shí)間,聽完電話聽音樂!...

如果需求變動(dòng)很大的情況下,而我們又用繼承的方式來實(shí)現(xiàn)這樣會(huì)導(dǎo)致一種現(xiàn)象:類爆炸(類數(shù)量激增)!并且繼承的層次可能會(huì)比較多~

所以,我們可以看到子類繼承父類這種方式來擴(kuò)展是十分局限的,不靈活的~

因此我們就有了裝飾模式!

1.2裝飾模式

首先我們來看看裝飾模式是怎么用的吧。

1.2.1前提代碼

電話接口:

// 一個(gè)良好的設(shè)計(jì)是抽取成接口或者抽象類的
public interface Phone {

    // 可以打電話
    void call();
}

具體的實(shí)現(xiàn)

public class IphoneX implements Phone {


    @Override
    public void call() {
        System.out.println("打電話給周圍的人關(guān)注公眾號(hào)Java3y");
    }
}
1.2.2包裝模式實(shí)現(xiàn)

上面我們已經(jīng)擁有了一個(gè)接口還有一個(gè)默認(rèn)實(shí)現(xiàn)。包裝模式是這樣干的:

首先我們弄一個(gè)裝飾器,它實(shí)現(xiàn)了接口,以組合的方式接收我們的默認(rèn)實(shí)現(xiàn)類

// 裝飾器,實(shí)現(xiàn)接口
public abstract class PhoneDecorate implements Phone {

    // 以組合的方式來獲取默認(rèn)實(shí)現(xiàn)類
    private Phone phone;
    public PhoneDecorate(Phone phone) {
        this.phone = phone;
    }

    @Override
    public void call() {
        phone.call();
    }
}

有了裝飾器以后,我們的擴(kuò)展都可以以裝飾器為基礎(chǔ)進(jìn)行擴(kuò)展,繼承裝飾器來擴(kuò)展就好了!

我們想要在打電話之前聽音樂

// 繼承著裝飾器來擴(kuò)展
public class MusicPhone extends PhoneDecorate {

    public MusicPhone(Phone phone) {
        super(phone);
    }

    // 定義想要擴(kuò)展的功能
    public void listenMusic() {

        System.out.println("繼續(xù)跑 帶著赤子的驕傲,生命的閃耀不堅(jiān)持到底怎能看到,與其茍延殘喘不如縱情燃燒");

    }

    // 重寫打電話的方法
    @Override
    public void call() {

        // 在打電話之前聽音樂
        listenMusic();
        super.call();
    }
}

現(xiàn)在我也想在打完電話后通知當(dāng)前的時(shí)間,于是我們也繼承裝飾類來擴(kuò)展

// 這里繼承的是MusicPhone裝飾器類
public class GiveCurrentTimePhone extends PhoneDecorate  {


    public GiveCurrentTimePhone(Phone phone) {
        super(phone);
    }

    // 自定義想要實(shí)現(xiàn)的功能:給出當(dāng)前的時(shí)間
    public void currentTime() {
        System.out.println("當(dāng)前的時(shí)間是:" + System.currentTimeMillis());
    }

    // 重寫要增強(qiáng)的方法
    @Override
    public void call() {
        super.call();
        // 打完電話后通知一下當(dāng)前時(shí)間
        currentTime();
    }
}

可以完成任務(wù):

目前這樣看起來,比我直接繼承父類要麻煩,而功能效果是一樣的....我們繼續(xù)往下看~~

此時(shí),我不想在打電話之前聽到彩鈴了,很簡單:我們不裝飾它就好了!

此時(shí),我想在打電話前報(bào)告一下時(shí)間,在打完電話之后聽彩鈴。

注意:雖然說要改動(dòng)類中的代碼,但是這種改動(dòng)是合理的。因?yàn)槲叶x出的GiveCurrentTimePhone類MusicPhone類本身從語義上就沒有規(guī)定擴(kuò)展功能的執(zhí)行順序

而繼承不一樣:先繼承Phone->實(shí)現(xiàn)MusicPhone->再繼承MusicPhone實(shí)現(xiàn)GiveCurrentTimePhone。這是固定的,從繼承的邏輯上已經(jīng)寫死了具體的代碼,是難以改變的。

所以我們還是可以很簡單地完成功能:

二、裝飾模式講解

可能有的同學(xué)在看完上面的代碼之后,還是迷迷糊糊地不知道裝飾模式是怎么實(shí)現(xiàn)“裝飾”的。下面我就再來解析一下:

第一步:我們有一個(gè)Phone接口,該接口定義了Phone的功能

第二步:我們有一個(gè)最簡單的實(shí)現(xiàn)類iPhoneX

第三步:寫一個(gè)裝飾器抽象類PhoneDecorate,以組合(構(gòu)造函數(shù)傳遞)的方式接收我們最簡單的實(shí)現(xiàn)類iPhoneX。其實(shí)裝飾器抽象類的作用就是代理(核心的功能還是由最簡單的實(shí)現(xiàn)類iPhoneX來做,只不過在擴(kuò)展的時(shí)候可以添加一些沒有的功能而已)。

第四步:想要擴(kuò)展什么功能,就繼承PhoneDecorate裝飾器抽象類,將想要增強(qiáng)的對(duì)象(最簡單的實(shí)現(xiàn)類iPhoneX或者已經(jīng)被增強(qiáng)過的對(duì)象)傳進(jìn)去,完成我們的擴(kuò)展!

再來看看下面的圖,就懂了!

往往我們的代碼可以省略起來,成了這個(gè)樣子(是不是和IO的非常像!)

    // 先增強(qiáng)聽音樂的功能,再增強(qiáng)通知時(shí)間的功能
    Phone phone = new GiveCurrentTimePhone(new MusicPhone(new IphoneX()));

結(jié)果是一樣的:

2.1裝飾模式的優(yōu)缺點(diǎn)

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

裝飾類和被裝飾類是可以獨(dú)立的,低耦合的。互相都不用知道對(duì)方的存在

裝飾模式是繼承的一種替代方案,無論包裝多少層,返回的對(duì)象都是is-a的關(guān)系(上面的例子:包裝完還是Phone類型)。

實(shí)現(xiàn)動(dòng)態(tài)擴(kuò)展,只要繼承了裝飾器就可以動(dòng)態(tài)擴(kuò)展想要的功能了。

缺點(diǎn):

多層裝飾是比較復(fù)雜的,提高了系統(tǒng)的復(fù)雜度。不利于我們調(diào)試~

三、總結(jié)

最后來補(bǔ)充一下包裝模式和代理模式的類圖:

對(duì)象增強(qiáng)的三種方式:

繼承

包裝模式

代理模式

那么只要遇到Java提供給我們的API不夠用,我們?cè)鰪?qiáng)一下就行了。在寫代碼時(shí),某個(gè)類被寫死了,功能不夠用,增強(qiáng)一下就可以了!

理解包裝模式,接下來就開始IO之旅咯~~~

參考資料:

《設(shè)計(jì)模式之禪》

https://wangjingxin.top/2016/10/21/decoration/

如果文章有錯(cuò)的地方歡迎指正,大家互相交流。習(xí)慣在微信看技術(shù)文章,想要獲取更多的Java資源的同學(xué),可以關(guān)注微信公眾號(hào):Java3y。為了大家方便,剛新建了一下qq群:742919422,大家也可以去交流交流。謝謝支持了!希望能多介紹給其他有需要的朋友

文章的目錄導(dǎo)航

https://zhongfucheng.bitcron.com/post/shou-ji/wen-zhang-dao-hang

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/69309.html

相關(guān)文章

  • 前端也要學(xué)系列:設(shè)計(jì)模式之裝飾者模式

    摘要:什么是裝飾者模式今天我們來講另外一個(gè)非常實(shí)用的設(shè)計(jì)模式裝飾者模式。就增加功能來說,裝飾者模式相比生成子類更為靈活。下面,裝飾者模式就要正式登場(chǎng)了。下一步,我們可以愉快的去使用裝飾者模式啦 什么是裝飾者模式 今天我們來講另外一個(gè)非常實(shí)用的設(shè)計(jì)模式:裝飾者模式。這個(gè)名字聽上去有些莫名其妙,不著急,我們先來記住它的一個(gè)別名:包裝器模式。 我們記著這兩個(gè)名字來開始今天的文章。 首先還是上《設(shè)計(jì)...

    高勝山 評(píng)論0 收藏0
  • 《JavaScript 模式》知識(shí)點(diǎn)小抄本(下)

    摘要:缺點(diǎn)不符合開閉原則,如果要改東西很麻煩,繼承重寫都不合適。預(yù)防低水平人員帶來的風(fēng)險(xiǎn)。開閉原則,高拓展性。這里的訂閱者稱為觀察者,而被觀察者稱為發(fā)布者,當(dāng)一個(gè)事件發(fā)生,發(fā)布者會(huì)發(fā)布通知所有訂閱者,并常常以事件對(duì)象形式傳遞消息。 介紹 最近開始給自己每周訂個(gè)學(xué)習(xí)任務(wù),學(xué)習(xí)結(jié)果反饋為一篇文章的輸出,做好學(xué)習(xí)記錄。 這一周(02.25-03.03)我定的目標(biāo)是《JavaScript 模式》...

    xiguadada 評(píng)論0 收藏0
  • 你不需要基于 CSS Grid 的柵格布局系統(tǒng)

    摘要:在過去的幾個(gè)星期里,我開始看到基于的布局框架和柵格系統(tǒng)的出現(xiàn)。你可能傾向于明確給出所有元素的位置,或是盡可能依賴于自動(dòng)布局。 showImg(https://segmentfault.com/img/remote/1460000010188997); 在過去的幾個(gè)星期里,我開始看到基于 CSS Grid 的布局框架和柵格系統(tǒng)的出現(xiàn)。我們驚訝它為什么出現(xiàn)的這么晚。但除了使用 CSS Gr...

    anonymoussf 評(píng)論0 收藏0
  • 你不需要基于 CSS Grid 的柵格布局系統(tǒng)

    摘要:在過去的幾個(gè)星期里,我開始看到基于的布局框架和柵格系統(tǒng)的出現(xiàn)。你可能傾向于明確給出所有元素的位置,或是盡可能依賴于自動(dòng)布局。 showImg(https://segmentfault.com/img/remote/1460000010188997); 在過去的幾個(gè)星期里,我開始看到基于 CSS Grid 的布局框架和柵格系統(tǒng)的出現(xiàn)。我們驚訝它為什么出現(xiàn)的這么晚。但除了使用 CSS Gr...

    gplane 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<