5.裝飾模式 Decorator (單一職責)

結合:
Android設計模式 006 裝飾者模式  【B站】對整個重構的細節講的容易懂
Android的設計模式-裝飾者模式   簡書結合安卓源碼講的還可以,讓我對context有更深入的理解

1.模式定義
    動態(組合)地給一個對象增加一些額外的職責。就增加功能而言,Decorator模式比生成子類(繼承)更為靈活(消除重複代碼&減少子類個數)。–《設計模式》GoF

2.動機

  • 在某些情況下我們可能會「過度地使用繼承來擴展對象的功能」,由於繼承為類型引入的靜態特質,使得這種擴展方式缺乏靈活性;並且隨着子類的增多(擴展功能的增多),各種子類的組合(擴展功能的組合)會導致更多子類的膨脹。
  • 如何使「對象功能的擴展」能夠根據需要來動態地實現?同時避免「擴展功能的增多」帶來的子類膨脹問題?從而使得任何「功能擴展變化」所導致的影響降為最低?

3.要點總結

  • 通過採用組合而非繼承的手法,Decorator模式實現了在運行時動態擴展對象功能的能力,而且可以根據需要擴展多個功能。避免了使用繼承帶來的「靈活性差」和「多子類衍生問題」。
  • Decorator類在接口上表現為is-a Component的繼承關係(繼承+組合),即Decorator類繼承了Component類所具有的接口。但在實現上又表現為has-a Component的組合關係,即Decorator類又使用了另外一個Component類。
  • Decorator模式的目的並非解決「多子類衍生的多繼承」問題,Decorator模式應用的要點在於解決「主體類在多個方向上擴展功能」–是為「裝飾」的含義。

4.uml類圖

5.實現

以絕地求生中槍械為例

5.1抽象槍械

public abstract class Gun {
    public abstract void load();//裝子彈

    public abstract void fire();//發射子彈
}

5.2具體槍械

98k 和m416
public class Gun98K extends Gun {
    @Override
    public void load() {
        Log.e("Gun98K", "裝滿5發子彈");
    }

    @Override
    public void fire() {
        Log.e("Gun98K", "開始點射");
    }
}

public class GunM416 extends Gun {

    @Override
    public void load() {
        Log.e("GunM416", "裝子彈");
    }

    @Override
    public void fire() {
        Log.e("GunM416", "開始掃射");
    }
}

5.3抽象裝飾器

public abstract class GunDecorator extends Gun {
    Gun gun;

    public GunDecorator(Gun gun) {
        this.gun = gun;
    }

    @Override
    public void load() {
        gun.load();
    }

    @Override
    public void fire() {
        gun.fire();
    }
}

5.4具體裝飾器

/**
 * Describe: 加槍托
 */
public class ButtGunDecorator extends GunDecorator {
    String butt;

    public ButtGunDecorator(Gun gun, String butt) {
        super(gun);
        this.butt = butt;
    }

    @Override
    public void load() {
        gun.load();
    }

    @Override
    public void fire() {
        Log.e("ButtGun", "降低垂直水平後坐力");
        gun.fire();
    }
}

/**
 * Created by nbb on 2020/12/26
 * Version 1.0
 * Describe:子彈袋裝飾
 */
public class BulletBagGunDecorator extends GunDecorator {

    String sight;

    public BulletBagGunDecorator(Gun gun, String sight) {
        super(gun);
        this.sight = sight;
    }

    @Override
    public void load() {
        Log.e("BulletBagGunDecorator", sight + "快速");
        gun.load();
    }

    @Override
    public void fire() {
        gun.fire();
    }
}

/**
 * Created by nbb on 2020/12/26
 * Version 1.0
 * Describe:瞄具
 */
public class SightGunDecorator extends GunDecorator {

    String sight;

    public SightGunDecorator(Gun gun, String sight) {
        super(gun);
        this.sight = sight;
    }

    @Override
    public  void load() {
        gun.load();
    }

    @Override
    public void fire() {
        Log.e("SightGun", sight + "打開 放大目標");
        gun.fire();
    }
}

5.5測試

  	Gun m416 = new GunM416();//撿到一把M4
    Gun sightM416 = new SightGunDecorator(m416, "4倍鏡");//撿到一個4倍鏡
    Gun buttSightM416 = new ButtGunDecorator(sightM416, "M416槍托");//撿到一個槍托
    
	buttSightM416.load();
    buttSightM416.fire();


	//撿到一把滿配98K
    Gun gun98k = new SightGunDecorator(new BulletBagGunDecorator(new Gun98K(),
  			"98k子彈袋"),"8倍鏡");
    gun98k.load();
    gun98k.fire();
//結果
//        GunM416: 裝子彈
//        ButtGun: 降低垂直水平後坐力
//        SightGun: 4倍鏡打開 放大目標
//        GunM416: 開始掃射

//        BulletBagGunDecorator: 98k子彈袋快速
//        Gun98K: 裝滿5發子彈
//        SightGun: 8倍鏡打開 放大目標
//        Gun98K: 開始點射