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: 開始點射