設計模式之裝飾者模式

程式設計師大彬發表於2023-02-04

本文已經收錄到Github倉庫,該倉庫包含計算機基礎、Java基礎、多執行緒、JVM、資料庫、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分散式、微服務、設計模式、架構、校招社招分享等核心知識點,歡迎star~

Github地址:https://github.com/Tyson0314/...


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

裝飾模式以對客戶端透明的方式擴充物件的功能,客戶端並不會覺得物件在裝飾前和裝飾後有什麼不同。裝飾模式可以在不創造更多子類的情況下,將物件的功能加以擴充套件。

比如設定FileInputStream,先用BufferedInputStream裝飾它,再用自己寫的LowerCaseInputStream過濾器去裝飾它。

InputStream in = new LowerCaseInputStream(new BufferedInputStream(new FileInputStream("test.txt")));

在裝飾模式中的角色有:

  • 抽象元件(Component)角色:給出一個抽象介面,以規範準備接收附加責任的物件。
  • 具體元件(ConcreteComponent)角色:定義一個將要接收附加責任的類。
  • 抽象裝飾(Decorator)角色:持有一個元件(Component)物件的例項,並定義一個與抽象元件介面一致的介面。
  • 具體裝飾(ConcreteDecorator)角色:負責給構件物件“貼上”附加的責任。

程式碼例項

LOL、王者榮耀等類Dota遊戲中,每次英雄升級都會附加一個額外技能點學習技能,這個就類似裝飾模式為已有類動態附加額外的功能。

具體的英雄就是ConcreteComponent,技能欄就是裝飾器Decorator,每個技能就是ConcreteDecorator。

新建一個介面:

public interface Hero {
    //學習技能
    void learnSkills();
}

建立介面的實現類(具體英雄盲僧):

//ConcreteComponent 具體英雄盲僧
public class BlindMonk implements Hero {
    
    private String name;
    
    public BlindMonk(String name) {
        this.name = name;
    }

    @Override
    public void learnSkills() {
        System.out.println(name + "學習了以上技能!");
    }
}

裝飾角色:

//Decorator 技能欄
public abstract class Skills implements Hero {
    
    //持有一個英雄物件介面
    private Hero hero;
    
    public Skills(Hero hero) {
        this.hero = hero;
    }

    @Override
    public void learnSkills() {
        if(hero != null)
            hero.learnSkills();
    }    
}

具體裝飾角色:

//ConreteDecorator 技能: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();
    }
}

//ConreteDecorator 技能: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();
    }
}
//ConreteDecorator 技能: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();
    }
}
//ConreteDecorator 技能: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();
    }
}

客戶端:

//客戶端:召喚師
public class Player {
    public static void main(String[] args) {
        //選擇英雄
        Hero hero = new BlindMonk("李青");
        
        Skills skills = new Skills(hero);
        Skills r = new Skill_R(skills,"猛龍擺尾");
        Skills e = new Skill_E(r,"天雷破/摧筋斷骨");
        Skills w = new Skill_W(e,"金鐘罩/鐵布衫");
        Skills q = new Skill_Q(w,"天音波/迴音擊");
        //學習技能
        q.learnSkills();
    }
}

輸出:

學習了技能Q:天音波/迴音擊
學習了技能W:金鐘罩/鐵布衫
學習了技能E:天雷破/摧筋斷骨
學習了技能R:猛龍擺尾
李青學習了以上技能!

最後給大家分享一個Github倉庫,上面有大彬整理的300多本經典的計算機書籍PDF,包括C語言、C++、Java、Python、前端、資料庫、作業系統、計算機網路、資料結構和演算法、機器學習、程式設計人生等,可以star一下,下次找書直接在上面搜尋,倉庫持續更新中~

Github地址https://github.com/Tyson0314/...

相關文章