設計模式-Decorator模式

Decorator(裝飾器)模式屬於結構型模式。
好比當其須要三種不一樣的附加特性,能夠爲其建立三個派生類。可是若它還須要同時具備其中兩種特性或者是各類特性的任意組合的時候,類繼承的方法就再也不適合了。
它容許向一個現有的對象不經過繼承來添加新的功能,同時又不改變其結構。git

一個例子(貪玩藍月)

前一陣子張家輝代言的《貪玩藍月》廣告火了,「我係喳喳輝,是兄弟就來砍我~」被洗腦到如今,正好用這個遊戲來解釋一下裝飾器模式。github

玩遊戲的人都知道這種類傳奇的遊戲核心玩法就是買裝備,打怪,升級,買裝備這樣反覆。設計模式

剛註冊帳號進入遊戲的玩家假設只有一條大褲衩,價值5金幣,隨着刷怪升級,身上的裝備也在一件件增多,這時候咱們須要知道身上的裝備價值多少金幣。ide

定義玩家組件化

public interface Gamer {
    /**
     * 獲取目前的裝備
     * @return
     */
    String getEquip();

    /**
     * 獲取目前身上裝備的價格
     * @return
     */
    int getPrice();
}

定義具體的法師職業玩家ui

public class MasterGamer implements Gamer {
    /**
     * 獲取目前的裝備
     *
     * @return
     */
    @Override
    public String getEquip() {
        return "大褲衩";
    }

    /**
     * 獲取目前身上裝備的價格
     *
     * @return
     */
    @Override
    public int getPrice() {
        return 5;
    }
}

新法師玩家出門只有大褲衩,裝備全靠打。this

傳統繼承實現

裝備「法師權杖」設計

public class TruncheonMasterGamer extends MasterGamer{
    /**
     * 獲取目前的裝備
     *
     * @return
     */
    @Override
    public String getEquip() {
        return super.getEquip()+",法師權杖";
    }

    /**
     * 獲取目前身上裝備的價格
     *
     * @return
     */
    @Override
    public int getPrice() {
        return super.getPrice()+50;
    }
}

繼續裝備「魔法斗篷」code

public class CloakTruncheonMasterGamer extends TruncheonMasterGamer{
    /**
     * 獲取目前的裝備
     *
     * @return
     */
    @Override
    public String getEquip() {
        return super.getEquip()+",魔法斗篷";
    }

    /**
     * 獲取目前身上裝備的價格
     *
     * @return
     */
    @Override
    public int getPrice() {
        return super.getPrice()+80;
    }
}

注意,這裏是在以前已經裝備了「法師權杖」之上去繼承。

計算裝備價格

CloakTruncheonMasterGamer gamer = new CloakTruncheonMasterGamer();
System.out.println("當前裝備:"+gamer.getEquip()+"\n裝備總價值:"+gamer.getPrice());

輸出結果

當前裝備:大褲衩,法師權杖,魔法斗篷
裝備總價值:135

裝飾器模式實現

image
聲明通用裝飾器基類「裝備」

public abstract class Equip implements Gamer {
    private Gamer gamer;

    public Equip(Gamer gamer) {
        this.gamer = gamer;
    }
    /**
     * 獲取目前的裝備
     *
     * @return
     */
    @Override
    public String getEquip() {
        return gamer.getEquip();
    }

    /**
     * 獲取目前身上裝備的價格
     *
     * @return
     */
    @Override
    public int getPrice() {
        return gamer.getPrice();
    }
}

具體裝飾器「法師權杖」

public class Truncheon extends Equip {
    public Truncheon(Gamer gamer) {
        super(gamer);
    }

    /**
     * 獲取目前的裝備
     *
     * @return
     */
    @Override
    public String getEquip() {
        return super.getEquip()+",法師權杖";
    }

    /**
     * 獲取目前身上裝備的價格
     *
     * @return
     */
    @Override
    public int getPrice() {
        return super.getPrice()+50;
    }
}

具體裝飾器「魔法斗篷」

public class Cloak extends Equip {
    public Cloak(Gamer gamer) {
        super(gamer);
    }

    /**
     * 獲取目前的裝備
     *
     * @return
     */
    @Override
    public String getEquip() {
        return super.getEquip()+",魔法斗篷";
    }

    /**
     * 獲取目前身上裝備的價格
     *
     * @return
     */
    @Override
    public int getPrice() {
        return super.getPrice()+80;
    }
}

計算裝備價格

//建立一個法師玩家
Gamer gamer = new MasterGamer();
//給法師玩家裝備法師權杖
gamer = new Truncheon(gamer);
//給法師玩家裝備魔法斗篷
gamer = new Cloak(gamer);
System.out.println("當前裝備:"+gamer.getEquip()+"\n裝備總價值:"+gamer.getPrice());

輸出結果

當前裝備:大褲衩,法師權杖,魔法斗篷
裝備總價值:135

對比

上面例子比較簡單,傳統繼承實現和裝飾器模式實現區別不是很明顯,但仔細思考仍是會發現一些區別:

  • 傳統繼承實現不自由,沒有「組件化」特性。玩家的裝備是能夠隨意組合,隨意拆卸的,而這種特性對於繼承來講只能經過各類各樣的子類組合來實現。就像上面的例子,裝備「法師權杖」和「魔法斗篷」須要在擁有「法師權杖」的基礎上再去繼承。
  • 裝飾器模式實現,使得附屬屬性和主體分開,而又不單獨存在(Equip類裏面聲明瞭Gamer對象)。裝備和玩家是分開的,能夠給玩家單獨裝備任何裝備,也能夠隨意卸下裝備。

總結

這種設計模式下不只能夠擴展一個類的功能,也能夠動態增長功能,動態撤銷。但缺點就是多層裝飾使用起來相對比較複雜。本質是將具體功能職責劃分(例如區分核心組件以及附加屬性職責)減小子類直接繼承父類的耦合性。


你能夠在這裏獲取相關代碼:設計模式-Decorator模式

相關文章
相關標籤/搜索