從零開始單排學設計模式「裝飾模式」黑鐵 I

閱讀本文大概須要 3.6 分鐘。

本篇是設計模式系列的第四篇,雖然以前也寫過相應的文章,可是由於種種緣由後來斷掉了,並且發現以前寫的內容也很渣,不夠系統。

因此如今打算重寫,加上距離如今也有一段時間了,也算是本身的一個回顧吧!

學而時習之,不亦說乎。

推薦閱讀:

目前段位:黑鐵 I


Let's Go!

前言

設計模式不是語法,是一種巧妙的寫法,能把程序變的更加靈活。架構模式比設計模式大,架構模式是戰略,而設計模式是戰術。

設計模式分爲3大類型:建立型,行爲型,結構型,總共有23種。

裝飾模式

裝飾模式(Decorator)指的是在沒必要改變類文件和使用繼承的狀況下,動態地擴展一個對象的功能。它是經過建立一個包裝對象,也就是裝飾來包裹真實的對象。

這種模式建立了一個裝飾類,用來包裝原有的類,並在保持類方法簽名完整性的前提下,提供了額外的功能。

業務需求

公司接到一個任務,須要爲某平臺開發一個搭配不一樣服飾的小項目,好比相似QQ、網絡遊戲或論壇都有的Avatar系統(爲了簡化代碼,直接使用控制檯模擬)。

代碼實現

通過公司的慎重討論(實際就幾秒鐘),開發這一個項目的重任,又當仁不讓的被產品經理交給了我,我:臉上笑嘻嘻,內心MMP。發一下下的小牢騷,不過仍是抓緊幹活。

思索一下,該系統要爲不一樣的人進行裝扮,因此定義一我的的類,不用每次裝扮其餘人時修改該類的代碼。

而後人身上要有不少的服飾,好比:大T恤、垮褲、鞋子等等,而後穿上以後,須要展現出來。因此這裏的話,能夠抽象出一個服飾的基類,而後各個具體的服飾都繼承該基類便可。

代碼以下:
Person類
/**
 * @author: LKP
 * @date: 2019/2/16
 */
public class Person {

    private String name;
    public Person() {
    }

    public Person(String name) {
        this.name = name;
    }

    public void show() {
        System.out.println("裝扮者:" + name);
    }
}複製代碼
服裝抽象類
/**
 * @author: LKP
 * @date: 2019/2/16
 */
public class Finery extends Person {

    protected  Person component;
    /**
     * 打扮
     * @param component
     */
    public void decorate(Person component){
        this.component = component;
    }

    @Override
    public void show() {
        if(null != component){
            component.show();
        }
    }
}複製代碼
具體服飾類
/**
 * @author: LKP
 * @date: 2019/2/16
 */
public class TShirts extends Finery {

    @Override
    public void show() {
        System.out.println("大T恤");
    }
}

class BigTrouser extends Finery {

    @Override
    public void show() {
        System.out.println("垮褲");
    }
}

class Sneakers extends Finery{

    @Override
    public void show() {
        System.out.println("破球鞋");
    }
}

class LeatherShoes extends Finery{

    @Override
    public void show() {
        System.out.println("皮鞋");
    }
}

class Tie extends Finery{

    @Override
    public void show() {
        System.out.println("領帶");
    }
}

class Suit extends Finery{

    @Override
    public void show() {
        System.out.println("西裝");
    }
}複製代碼
這裏內部類,只是爲了較少代碼量,實際開發中可不要偷懶,按實際來建立。

客戶端代碼
/**
 * @author: LKP
 * @date: 2019/2/16
 */
public class Main {

    public static void main(String[] args) {

        Person person = new Person("孤獨鍵客");

        System.out.println("第一種裝扮:");

        Finery tShirts = new TShirts();
        Finery bigTrouser = new BigTrouser();
        Finery sneakers = new Sneakers();

        tShirts.show();
        bigTrouser.show();
        sneakers.show();
        person.show();

        System.out.println("\n第二種裝扮:");

        Finery suit = new Suit();
        Finery tie = new Tie();
        Finery leatherShoes = new LeatherShoes();

        suit.show();
        tie.show();
        leatherShoes.show();
        person.show();
    }
}複製代碼

代碼簡單搞定,接下來來看一下運行結果


搞定收工,審視一下,自我感受還算不錯,若是新裝扮只需改變一下調用順序便可,若是又新人物,只需從新new一個Person類就能夠了。

接下里將項目提交上傳,而後告訴leader一聲,over,離下班時間還早,好像還能夠作點其餘的事情~。

正當你準備打開去幹點其餘事情,leader回覆你了:

leader:「你仔細看看這段代碼,這樣寫意味着什麼?

你想象一下,是否是把‘大T恤’、‘垮褲’、‘破球鞋’、‘裝扮者’一個一個詞顯示出來,是否是至關於你光着身子,一個一個把這些穿上,這可有點像脫衣舞哦~」。

我:「你意思是,這些應該都在內部組裝完畢,而後在顯示出來?」。

leader:"賓果,並且還要按照正確的順序串聯起來控制,這裏有點難度,修改好以後再給我"。

這彷佛和某種設計模式有關,難道是建造者模式嗎?不對,建造者模式要求建造的過程必須是穩定的,而這個穿搭的過程是不固定的,一個有個性的人又無數種方案。

通過一番查找,這偏偏最適合用裝飾模式了。

咱們修改一下具體的服飾類
/**
 * @author: LKP
 * @date: 2019/2/16
 */
public class TShirts extends Finery {

    @Override
    public void show() {
        System.out.println("大T恤");
        super.show();
    }
}

class BigTrouser extends Finery {

    @Override
    public void show() {
        System.out.println("垮褲");
        super.show();
    }
}

class Sneakers extends Finery{

    @Override
    public void show() {
        System.out.println("破球鞋");
        super.show();
    }
}

class LeatherShoes extends Finery{

    @Override
    public void show() {
        System.out.println("皮鞋");
        super.show();
    }
}

class Tie extends Finery{

    @Override
    public void show() {
        System.out.println("領帶");
        super.show();
    }
}

class Suit extends Finery{

    @Override
    public void show() {
        System.out.println("西裝");
        super.show();
    }
}複製代碼
再修改一下客戶端代碼:
/**
 * @author: LKP
 * @date: 2019/2/16
 */
public class Main {

    public static void main(String[] args) {

        Person person = new Person("孤獨鍵客");
        System.out.println("第一種裝扮:");
        Sneakers sneakers = new Sneakers();
        BigTrouser bigTrouser = new BigTrouser();
        TShirts tShirts = new TShirts();
        sneakers.decorate(person);
        bigTrouser.decorate(sneakers);
        tShirts.decorate(bigTrouser);
        tShirts.show();
        System.out.println("第二種裝扮:");
        LeatherShoes leatherShoes = new LeatherShoes();
        Tie tie = new Tie();
        Suit suit = new Suit();
        leatherShoes.decorate(person);
        tie.decorate(leatherShoes);
        suit.decorate(tie);
        suit.show();
    }
}複製代碼
第二版的程序寫完了,來測試一下

完美搞定,哈哈,我還能夠換種裝飾方式

看下結果

光着膀子、打着領帶、下身垮褲、腳上皮鞋,絕對的極具個性。

最後,完美搞定,提交代碼~~~

裝飾模式UML類圖



總結

來總結一下裝飾模式:

主要解決:通常的,咱們爲了擴展一個類常用繼承方式實現,因爲繼承爲類引入靜態特徵,而且隨着擴展功能的增多,子類會很膨脹。

什麼時候使用:在不想增長不少子類的狀況下擴展類。

如何解決:將具體功能職責劃分,同時繼承裝飾者模式。

關鍵代碼: 一、Component 類充當抽象角色,不該該具體實現。 二、修飾類引用和繼承 Component 類,具體擴展類重寫父類方法。

應用實例: 一、孫悟空有 72 變,當他變成"廟宇"後,他的根本仍是一隻猴子,可是他又有了廟宇的功能。 二、不論一幅畫有沒有畫框均可以掛在牆上,可是一般都是有畫框的,而且其實是畫框被掛在牆上。在掛在牆上以前,畫能夠被蒙上玻璃,裝到框子裏;這時畫、玻璃和畫框造成了一個物體。

優勢:裝飾類和被裝飾類能夠獨立發展,不會相互耦合,裝飾模式是繼承的一個替代模式,裝飾模式能夠動態擴展一個實現類的功能。

缺點:多層裝飾比較複雜。

使用場景: 一、擴展一個類的功能。 二、動態增長功能,動態撤銷。

注意事項:可代替繼承。



往期精彩回顧


歡迎關注個人公衆號「程序員的成長之路」,閱讀更多精彩!
相關文章
相關標籤/搜索