天天看點

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

作者:java研習社
設計模式第三篇-裝飾者模式

一、引言

先看一個開發問題,很多人都玩過英雄聯盟這款遊戲:裡面有各種英雄,每個英雄都有各自的技能(一般是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類就是用的裝飾者模式

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

為幫助開發者們提升面試技能、有機會入職BATJ等大廠公司,特别制作了這個專輯——這一次整體放出。

大緻内容包括了: Java 集合、JVM、多線程、并發程式設計、設計模式、Spring全家桶、Java、MyBatis、ZooKeeper、Dubbo、Elasticsearch、Memcached、MongoDB、Redis、MySQL、RabbitMQ、Kafka、Linux、Netty、Tomcat等大廠面試題等、等技術棧!

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

歡迎大家關注頭條【java研習社】,回複【111】,擷取以上最新Java後端架構VIP學習資料以及視訊學習教程,然後一起學習,一文在手,面試我有。

每一個專欄都是大家非常關心,和非常有價值的話題,如果我的文章對你有所幫助,還請幫忙點贊、好評、轉發一下,你的支援會激勵我輸出更高品質的文章,非常感謝!

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

繼續閱讀