5.装饰模式 Decorator (单一职责)
结合:
Android设计模式 006 装饰者模式 【B站】对整个重构的细节讲的容易懂
Android的设计模式-装饰者模式 【简书】结合安卓源码讲的还可以,让我对context有更深入的理解
模式定义
动态(组合)地给一个对象增加一些额外的职责。就增加功能而言,Decorator模式比生成子类(继承)更为灵活(消除重复代码&减少子类个数)。--《设计模式》GoF
动机
- 在某些情况下我们可能会“过度地使用继承来扩展对象的功能”,由于继承为类型引入的静态特质,使得这种扩展方式缺乏灵活性;并且随着子类的增多(扩展功能的增多),各种子类的组合(扩展功能的组合)会导致更多子类的膨胀。
- 如何使“对象功能的扩展”能够根据需要来动态地实现?同时避免“扩展功能的增多”带来的子类膨胀问题?从而使得任何“功能扩展变化”所导致的影响降为最低?
要点总结
- 通过采用组合而非继承的手法,Decorator模式实现了在运行时动态扩展对象功能的能力,而且可以根据需要扩展多个功能。避免了使用继承带来的“灵活性差”和“多子类衍生问题”。
- Decorator类在接口上表现为is-a Component的继承关系(继承+组合),即Decorator类继承了Component类所具有的接口。但在实现上又表现为has-a Component的组合关系,即Decorator类又使用了另外一个Component类。
- Decorator模式的目的并非解决“多子类衍生的多继承”问题,Decorator模式应用的要点在于解决“主体类在多个方向上扩展功能”--是为“装饰”的含义。
uml类图
实现
以绝地求生中枪械为例
抽象枪械
public abstract class Gun {
public abstract void load();//装子弹
public abstract void fire();//发射子弹
}
具体枪械
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", "开始扫射");
}
}
抽象装饰器
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();
}
}
具体装饰器
/**
* 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();
}
}
测试
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: 开始点射