1. 程式人生 > >設計模式第三篇-裝飾者模式

設計模式第三篇-裝飾者模式

一、引言

先看一個開發問題,很多人都玩過英雄聯盟這款遊戲:裡面有各種英雄,每個英雄都有各自的技能(一般是4個主動技能),每升一級可以升級一個技能,但是可升級的技能不固定。我們需要通過技能狀態來計算傷害,這個時候組合就非常多了(理論上是英雄數*技能數)。如果用繼承來解決的話,那麼子類就爆炸多了。

除了繼承還有一種設計,就是在基類上增加布爾變數,如Q,E等,然後提供一些has(get)和set方法來設定這些布林值,子類裡通過擴充套件計算傷害值,這個看起來是一個可行的設計,但這個設計也會有一些問題。

1.每個技能可以多次加點,單純靠布林值是處理不了的。

2.技能有可能會進行調整,那麼我們就必須通過修改基類來處理。

3.遊戲裡面還有裝備這種情況,增加裝備也是相當於多了技能(貌似用裝備來做例子更合適)。。。

我們用更好的方法來解決這個問題

這個問題的本質是擴充套件,我們想要擴充套件一些功能,但是不想用繼承。裝飾者模式可以解決這個問題

二、裝飾者模式

定義:動態地將責任附加到物件上。若要擴充套件功能,裝飾者提供了比繼承更有彈性的替代方案。

意圖:動態地給一個物件新增一些額外的職責。就增加功能來說,裝飾器模式相比生成子類更為靈活。

主要解決:一般的,我們為了擴充套件一個類經常使用繼承方式實現,由於繼承為類引入靜態特徵,並且隨著擴充套件功能的增多,子類會很膨脹。

何時使用:在不想增加很多子類的情況下擴充套件類。

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

裝飾者通用類圖:

 

三、實現

英雄聯盟遊戲實現

//抽象基類
public abstract class Hero {
    //學習技能
    public abstract void learnSkills();
}

//具體英雄蘭博,需要被擴充套件的類
public class Lanbo extends Hero {
    //英雄屬性
    private String name;

    public Lanbo(String name){
        this.name = name;
    }
    @Override
    
public void learnSkills() { System.out.println(name + "學習了以上技能!"); } } //抽象技能類,裝飾者的抽象基類 public abstract class Skills extends Hero { private Hero hero; public Skills(Hero hero){ this.hero = hero; } @Override public void learnSkills() { if(hero!=null){ hero.learnSkills(); } } } //具體裝飾子類,用來裝飾 Q技能 public class Skill_Q extends Skills { private String skillName; public Skill_Q(Hero hero,String skillName) { super(hero); this.skillName=skillName; } @Override public void learnSkills() { System.out.println("學習了技能Q:" +skillName); super.learnSkills(); } } //具體裝飾子類,用來裝飾 W技能 public class Skill_W extends Skills { private String skillName; public Skill_W(Hero hero,String skillName) { super(hero); this.skillName=skillName; } @Override public void learnSkills() { System.out.println("學習了技能W:" +skillName); super.learnSkills(); } } //具體裝飾子類,用來裝飾E技能 public class Skill_E extends Skills { private String skillName; public Skill_E(Hero hero,String skillName) { super(hero); this.skillName=skillName; } @Override public void learnSkills() { System.out.println("學習了技能E:" +skillName); super.learnSkills(); } } //具體裝飾子類,用來裝飾R技能 public class Skill_R extends Skills { private String skillName; public Skill_R(Hero hero,String skillName) { super(hero); this.skillName=skillName; } @Override public void learnSkills() { System.out.println("學習了技能R:" +skillName); super.learnSkills(); } }

執行:

        //選擇英雄
        Hero hero = new Lanbo("蘭博");
        Skills q = new Skill_Q(hero,"縱火盛宴");
        Skills w = new Skill_W(q,"破碎護盾");
        Skills e = new Skill_E(w,"電子魚叉");
        Skills r = new Skill_R(e,"恆溫灼燒");
        //學習技能
        r.learnSkills();

執行結果:

四、總結

優點

  1. 裝飾這模式和繼承的目的都是擴充套件物件的功能,但裝飾者模式比繼承更靈活
  2. 通過使用不同的具體裝飾類以及這些類的排列組合,設計師可以創造出很多不同行為的組合
  3. 裝飾者模式有很好地可擴充套件性

缺點:裝飾者模式會導致設計中出現許多小物件,如果過度使用,會讓程式變的更復雜。並且更多的物件會是的差錯變得困難,特別是這些物件看上去都很像。

java.io類就是用的裝飾者模式

 

 

 相關程式碼:https://gitee.com/yuanqinnan/pattern