1. 程式人生 > >Android設計模式之一個例子讓你徹底明白裝飾者模式(Decorator Pattern)

Android設計模式之一個例子讓你徹底明白裝飾者模式(Decorator Pattern)

導讀

這篇文章中我不會使用概念性文字來說明裝飾者模式,因為通常概念性的問題都很抽象,很難懂,使得讀者很難明白到底為什麼要使用這種設計模式,我們設計模式的誕生,肯定是前輩們在設計程式的時候遇到了某種困難,為了避免這種苦難的發生,從而設計出來的這種設計模式,所以這篇文章中我會帶領大家遇見這種困難,從而使用設計模式解決這種困難,最後大家就會明白什麼是設計者模式,什麼時候應該使用設計者模式以及如何使用設計者模式了

首先我們先來看一下裝飾者模式的UML圖是什麼樣子的,圖中各個類的含義不懂沒有關係,下面我會用一個形象的例子來一一介紹他們,相信大家看完後肯定就明白了
這裡寫圖片描述

如果不用裝飾者設計模式會出現什麼問題?

這裡我不準備用一些概念性的文字來說明什麼是裝飾者模式,我就要用一個實際的例子來形象的說明什麼是裝飾者模式!
比如我們玩網路遊戲,我們都要先建立一個角色對吧,這些角色每個人創建出來的都不一樣,因為角色肯定可以根據使用者的審美來個性化打造,但是每個角色最開始的能力都是一樣的,不會因為一個玩家給他捏了一張特別帥的臉而變得特別的厲害。那麼這個角色肯定是一個介面,這就是UML圖中的Conponent介面

/**
 * 遊戲角色
 */
public interface Avatar {
    String describe();
}

非常簡單,只有一個方法,我們只用來演示,真正的遊戲角色不可能只有這麼簡單。describe方法用來描述這個角色。

好,我們玩遊戲肯定有職業對吧,假設我們這款遊戲只設計了4種職業:戰士(Worrior),法師(Mage),獵人(Hunter),術士(Warlock)。我們要建立4個實現類,這就對應ConcreteComponent類

public class Worrior implements Avatar {
    @Override
    public String describe() {
        return "戰士";
    }
}
public class Mage implements Avatar {
    @Override
    public String describe
() { return "法師"; } }
public class Hunter implements Avatar {
    @Override
    public String describe() {
        return "獵人";
    }
}
public class WarLock implements Avatar {
    @Override
    public String describe() {
        return "術士";
    }
}

好了,現在我們已經建立好4種職業的遊戲角色了。現在我們的玩家覺得太單調了,所有同樣職業的角色都長一個樣子,你們應該允許我們在建立角色的時候可以修改角色的外觀。比如選擇頭髮顏色。

這可怎麼辦,我們有4種職業啊,每種職業提供3種顏色的頭髮,我們得再建立12個子類啊,而且之前設計的4個實現類的作用也就不大了,因為大家肯定都去改變一下頭髮的顏色。好,先硬著頭皮來寫吧。

public class WorriorWithRedHair implements Avatar{

    @Override
    public String describe() {
        return "戰士+紅顏色頭髮";
    }
}
public class WorriorWithGreenHair implements Avatar{

    @Override
    public String describe() {
        return "戰士+綠顏色頭髮";
    }
}
public class WorriorWithBlueHair implements Avatar{

    @Override
    public String describe() {
        return "戰士+藍顏色頭髮";
    }
}

public class MageWithRedHair implements Avatar{

    @Override
    public String describe() {
        return "法師+紅顏色頭髮";
    }
}
public class MageWithGreenHair implements Avatar{

    @Override
    public String describe() {
        return "法師+綠顏色頭髮";
    }
}
public class MageWithBlueHair implements Avatar{

    @Override
    public String describe() {
        return "法師+藍顏色頭髮";
    }

public class HunterWithRedHair implements Avatar{

    @Override
    public String describe() {
        return "獵人+紅顏色頭髮";
    }
}
public class HunterWithGreenHair implements Avatar{

    @Override
    public String describe() {
        return "獵人+綠顏色頭髮";
    }
}
public class HunterWithBlueHair implements Avatar{

    @Override
    public String describe() {
        return "獵人+藍顏色頭髮";
    }

public class WarLockWithRedHair implements Avatar{

    @Override
    public String describe() {
        return "術士+紅顏色頭髮";
    }
}
public class WarLockWithGreenHair implements Avatar{

    @Override
    public String describe() {
        return "術士+綠顏色頭髮";
    }
}
public class WarLockWithBlueHair implements Avatar{

    @Override
    public String describe() {
        return "術士+藍顏色頭髮";
    }

好了,加班到半夜,終於寫完了。第二天上班,老闆來找你了,現在我們的玩家越來越多了,他們反映說我們的角色還是太單調,我們還要讓玩家可以選擇上衣的顏色和褲子的顏色,上衣有5種顏色,褲子有5種顏色。聽完這個需求,我想你也應該吐血了。比如玩家A會選擇戰士+紅色頭髮+白色上衣+藍色褲子,玩家B會選擇術士+藍色頭髮+白色上衣+黃色褲子。這組合也太多了,這得寫多少個實現類。這種方法肯定是行不通的。

使用裝飾者模式如何解決問題?

這時公司來了個大牛,他聽說了這個情況,接下了這個需求,你心想他一定是瘋了,可是第二天他就完成了任務,你吃了一大驚,趕緊去看他的程式碼是怎麼實現的,原來這位大牛使用了你連聽都沒說過的裝飾者設計模式。

首先他設計了一個類,實現了Avatar介面,並且傳入了一個Avatar物件,這就對應UML圖中的Decorator

public class AvatarDecorator implements Avatar {
    private Avatar av;
    public AvatarDecorator(Avatar avatar){
        av = avatar;
    }

    @Override
    public String describe() {
        return av.describe();
    }
}

我們看到他裡面持有一個Avatar型別的物件,在describe方法中實際呼叫的也是av的describe物件,我們傳入的Avatar物件也就是我們需要進行裝飾的物件了。

好,現在我們先來設計頭髮顏色的裝飾類

public class RedHair extends AvatarDecorator {
    public RedHair(Avatar avatar) {
        super(avatar);
    }

    @Override
    public String describe() {
        return super.describe()+"+紅色頭髮";
    }
}
public class GreenHair extends AvatarDecorator {
    public GreenHair(Avatar avatar) {
        super(avatar);
    }

    @Override
    public String describe() {
        return super.describe()+"+綠色頭髮";
    }
}
public class BlueHair extends AvatarDecorator {
    public BlueHair(Avatar avatar) {
        super(avatar);
    }

    @Override
    public String describe() {
        return super.describe()+"+藍色頭髮";
    }
}

我們看到,我們的構造方法是呼叫的super()的構造方法,也就是呼叫的AvatarDecorator的構造方法,我們的describe中也先呼叫了super.describe()然後後面加上了我們的裝飾內容,也就是說我們傳進來的一個Avatar物件被我們裝飾了。這就相當於UML中的ConcreteDecorator。

好了,現在玩家想要建立一個角色的話就可以這樣創建出來

//紅色頭髮戰士
Avatar avatar1 = new RedHair(new Worrior());
//綠色頭髮術士
Avatar avatar2 = new GreenHair(new WarLock());

接下來我們再設計上衣和褲子的裝飾類

public class WhiteJacket extends AvatarDecorator {
    public WhiteJacket(Avatar avatar) {
        super(avatar);
    }

    @Override
    public String describe() {
        return super.describe()+"+白色上衣";
    }
}
public class RedJacket extends AvatarDecorator {
    public RedJacket(Avatar avatar) {
        super(avatar);
    }

    @Override
    public String describe() {
        return super.describe()+"+紅色上衣";
    }
}public class BlackJacket extends AvatarDecorator {
    public BlackJacket(Avatar avatar) {
        super(avatar);
    }

    @Override
    public String describe() {
        return super.describe()+"+黑色上衣";
    }
}public class GreenJacket extends AvatarDecorator {
    public GreenJacket(Avatar avatar) {
        super(avatar);
    }

    @Override
    public String describe() {
        return super.describe()+"+綠色上衣";
    }
}public class BlueJacket extends AvatarDecorator {
    public BlueJacket(Avatar avatar) {
        super(avatar);
    }

    @Override
    public String describe() {
        return super.describe()+"+藍色上衣";
    }
}
public class WhitePants extends AvatarDecorator {
    public WhitePants(Avatar avatar) {
        super(avatar);
    }

    @Override
    public String describe() {
        return super.describe()+"+白色褲子";
    }
}
public class BlackPants extends AvatarDecorator {
    public BlackPants(Avatar avatar) {
        super(avatar);
    }

    @Override
    public String describe() {
        return super.describe()+"+黑色褲子";
    }
}
public class RedPants extends AvatarDecorator {
    public RedPants(Avatar avatar) {
        super(avatar);
    }

    @Override
    public String describe() {
        return super.describe()+"+紅色褲子";
    }
}
public class GreenPants extends AvatarDecorator {
    public GreenPants(Avatar avatar) {
        super(avatar);
    }

    @Override
    public String describe() {
        return super.describe()+"+綠色褲子";
    }
}
public class BluePants extends AvatarDecorator {
    public BluePants(Avatar avatar) {
        super(avatar);
    }

    @Override
    public String describe() {
        return super.describe()+"+藍色褲子";
    }
}

好了,現在我們就可以任意組合我們的角色了

 //綠色頭髮獵人穿著白色上衣和黑色褲子
        Avatar avatar3 = new GreenHair(new WhiteJacket(new BlackPants(new Hunter())));
        //紅色頭髮法師穿著紅色上衣和白色褲子
        Avatar avatar4 = new RedHair(new RedJacket(new WhitePants(new Mage())));

有圖有真相

這裡寫圖片描述