<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          設(shè)計(jì)模式詳解——裝飾者模式

          共 3295字,需瀏覽 7分鐘

           ·

          2021-10-16 15:32

          前言

          在程序開發(fā)設(shè)計(jì)中,有一個特別重要的原則是,類應(yīng)該對擴(kuò)展開放,對修改關(guān)閉,雖然這一原則聽起來很矛盾,但是在一些比較優(yōu)秀的設(shè)計(jì)模式中,是完全可以達(dá)成這一原則的,比如裝飾者模式,它就是這一原則的最佳實(shí)踐,下面我們來看下它的基本原理和用法,希望能通過這篇內(nèi)容,引發(fā)給位小伙伴對于設(shè)計(jì)模式的思考。

          裝飾者模式

          裝飾者模式動態(tài)地將責(zé)任附加到對象上,若要擴(kuò)展功能,裝飾者提供了比繼承更有彈性的替代方案。

          要點(diǎn)

          • 繼承屬于擴(kuò)展形式之一,但不見得是達(dá)到彈性設(shè)計(jì)的最佳方式;
          • 在我們的設(shè)計(jì)中,應(yīng)該允許行為可以被擴(kuò)展,而無須修改現(xiàn)有代碼
          • 組合和委托可用于在運(yùn)行時動態(tài)地加上新的行為
          • 除了繼承,裝飾者模式也可以讓我們擴(kuò)展行為
          • 裝飾者模式意味著一群裝飾者類,這些類用來包裝具體組件
          • 裝飾者類反映出被裝飾組件的類型(他們具有相同的類型,都經(jīng)過接口或繼承實(shí)現(xiàn))
          • 裝飾者可以在被裝飾者的行為前面或者后面加上自己的行為,甚至將被裝飾者的行為整體覆蓋,從而達(dá)到特定目的
          • 裝飾者一般對組件的客戶是透明的,除非客戶程序依賴于組件的具體類型
          • 裝飾者會導(dǎo)致設(shè)計(jì)中出現(xiàn)許多小對象,如果過度使用,會讓程序變得復(fù)雜。

          示例代碼

          原始對象接口

          基類接口,也是包裝類最底層的內(nèi)容(俄羅斯套娃里面第一個被套的那個),也可以理解為包裝類中的最小單位,這里我們用形狀這個抽象概念作為示例演示。

          首先這個抽象接口有一個基本方法,就是draw繪制方法,凡是實(shí)現(xiàn)了形狀這個接口的所有類都必須實(shí)現(xiàn)這個接口。

          public?interface?Shape?{
          ????/**
          ?????*?繪制方法
          ?????*/

          ????void?draw();
          }
          接口實(shí)現(xiàn)

          這里是接口的實(shí)現(xiàn),不過為了方便理解,各位小伙伴可以把接口的實(shí)現(xiàn)當(dāng)作第一層包裝類,這一層包裝相當(dāng)于直接確定了我們形狀的基本屬性,表明它是一個圓形。

          public?class?Circle?implements?Shape?{
          ????@Override
          ????public?void?draw()?{
          ????????System.out.println("繪制圓形");
          ????}
          }

          同理,這里確定了我們的形狀為矩形。

          public?class?Rectangle?implements?Shape?{
          ????@Override
          ????public?void?draw()?{
          ????????System.out.println("繪制矩形");
          ????}
          }
          裝飾對象抽象

          這里相當(dāng)于做一個通用的包裝接口,后續(xù)的包裝類只需要繼承這個抽象類,然后再在其中加入新的行為或?qū)傩约纯桑恍枰貜?fù)封裝。

          public?abstract?class?ShapeDecorator?implements?Shape?{
          ????protected?Shape?decoratedShape;

          ????public?ShapeDecorator(Shape?decoratedShape){
          ????????this.decoratedShape?=?decoratedShape;
          ????}

          ????public?void?draw(){
          ????????decoratedShape.draw();
          ????}
          }
          裝飾者實(shí)現(xiàn)

          這里就是第一層包裝(如果按我們上面的說法應(yīng)該是第三層,因?yàn)槲覀儌鬟f的肯定是shape的實(shí)現(xiàn),而不是抽象接口),這里繼承了上面的抽象包裝類。

          public?class?RedShapeDecorator?extends?ShapeDecorator?{

          ????public?RedShapeDecorator(Shape?decoratedShape)?{
          ????????super(decoratedShape);
          ????}

          ????@Override
          ????public?void?draw()?{
          ????????decoratedShape.draw();
          ????????setRedBorder(decoratedShape);
          ????}

          ????private?void?setRedBorder(Shape?decoratedShape){
          ????????System.out.println("Border?Color:?Red");
          ????}
          }

          同時引入了一個新的方法setRedBorder,這個方法讓我們的形狀有了一個新的屬性——紅色。當(dāng)然,我們還可以繼續(xù)封裝,我們可以在顏色的基礎(chǔ)上給他封裝一個尺寸:

          public?class?SizeShapeDecorator?extends?RedShapeDecorator{

          ????public?SizeShapeDecorator(Shape?decoratedShape)?{
          ????????super(decoratedShape);
          ????}

          ????@Override
          ????public?void?draw()?{
          ????????super.draw();
          ????????setSize(decoratedShape);
          ????}

          ????private?void?setSize(Shape?decoratedShape)?{
          ????????System.out.println("size:?100");
          ????}
          }
          測試代碼

          這里我們分別創(chuàng)建一個圓形和矩形,指定不同的包裝類,并調(diào)用他們的draw方法:

          ?@Test
          ????public?void?testDecorator()?{
          ????????Shape?circle?=?new?Circle();
          ????????ShapeDecorator?redCircle?=?new?RedShapeDecorator(new?Circle());
          ????????ShapeDecorator?redRectangle?=?new?RedShapeDecorator(new?Rectangle());
          ????????ShapeDecorator?sizeRedRectangle?=?new?SizeShapeDecorator(new?Rectangle());
          ????????System.out.println("原始圓形");
          ????????circle.draw();

          ????????System.out.println("===========\n包裝的紅色圓形");
          ????????redCircle.draw();

          ????????System.out.println("===========\n包裝的紅色矩形");
          ????????redRectangle.draw();?
          ????????
          ????????System.out.println("===========\n包裝的100紅色矩形");
          ????????sizeRedRectangle.draw();
          ????}

          最后運(yùn)行結(jié)果如下:

          總結(jié)

          從示例代碼及運(yùn)行結(jié)果我們可以看出來,雖然后續(xù)我們不斷為原始的形狀加入了新的屬性,但是我們并沒有改變原始代碼,而是一層一層地添加不同的包裝類,然后讓它逐步有了更多的新屬性。

          這樣的操作好處是,我們原有的形狀擁有了新的屬性,但這些后增加的屬性和原始形狀之間并沒有任何強(qiáng)依賴關(guān)系,也沒有破壞原因業(yè)務(wù)邏輯,保證了系統(tǒng)的可擴(kuò)展性,同時耦合性還很低,這就是裝飾者設(shè)計(jì)模式的魅力。

          不知道各位小伙伴是否還記得我們前段時間分享的spring boot源碼相關(guān)內(nèi)容,spring boot的源碼中就用到了裝飾者模式,比如BeanFactory的相關(guān)內(nèi)容,另外我們?nèi)粘i_發(fā)過程中用到的Tomcat有好多地方也用到了這種設(shè)計(jì)模式,最典型的是ServletRequestServletResponse

          - END -


          瀏覽 24
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  人妻一区二区三区 | 在线浏览亚洲性图 | 久久ww| xxxxx 91 | av天堂资源在线 A片免费观看网站 |