装饰器模式(Decorator Pattern)

若要扩展功能,装饰者提供了比集成更有弹性的替代方案,动态地将责任附加到对象上。

核心结构

装饰器模式(Decorator Pattern) 的核心在于在不修改已有实现的前提下,对其进行增强。这里体现了一个原则:类应该对扩展开放,对修改关闭

应用场景

  • 当需要在不修改原有对象的前提下为其添加新功能时。
  • 当子类扩展不切实际时(比如需要多个可选功能组合的情况)。
  • 在Java IO流中大量使用了装饰器模式,例如BufferedInputStream(InputStream)就是对输入流的一种装饰。

需求

设计游戏的装备系统,要求可以计算出每种装备在镶嵌了各种宝石后的攻击力和描述:

  • 按照要求,构建如下UML类图,其中包含装备超类Equip、装饰超类EquipDecorator、游戏属性角色如下:
装备 红宝石(hp+) 蓝宝石(mp+) 绿宝石(sp+) 黄宝石(ak+) 紫宝石(df+)
帽子🧢
上衣👔
护甲🧥
裤子👖
鞋子👢
武器🗡

根据属性栏,设计装备属性,有攻击、敏捷、防御、hp/mp值。其中红宝石+hp,蓝宝石+mp,绿宝石+敏捷,黄宝石+攻击力,紫宝石+防御力。

装饰器可以多层嵌套,例如获取得到的宝石都用在武器的加点上,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Equip levelUpWeapon = new RedGem(new BlueGem(new YellowGem(new GreenGem(new WwaponEquip()))));
// 创建剑士并穿戴该氪金武器
Swordman swordman = new Swordman();
swordman.equip(levelUpWeapon);

System.out.println(swordman);

Swordman{
attack=12,
defense=0,
speed=5,
hp=5,
mp=10,
equipment=已装备有:🗡
}

下面是示例代码的部分实现:

被装饰的类以及其超类,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public interface Equip {
EquipType getType();
int attack();
int speed();
int defense();
int hp();
int mp();
String description();
}

public class WeaponEquip implements Equip {
@Override
public EquipType getType() {
return EquipType.WEAPON;
}
@Override
public int attack() {
return 0;
}
@Override
public int speed() {
return 0;
}
@Override
public int defense() {
return 0;
}
@Override
public int hp() {
return 0;
}
@Override
public int mp() {
return 0;
}
@Override
public String description() {
return "🗡";
}
}

实现其装饰器,可以为interfaceabstract

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public abstract class EquipDecorator implements Equip {
protected Equip equip;
protected EquipDecorator(Equip equip) {
this.equip = equip;
}
@Override
public int attack() {
return equip.attack();
}
@Override
public int speed() {
return equip.speed();
}
@Override
public int defense() {
return equip.defense();
}
@Override
public int hp() {
return equip.hp();
}
@Override
public int mp() {
return equip.mp();
}
@Override
public String description() {
return equip.description();
}
}

按照定义,装饰器模式(decorator pattern) 在不改变已有类的前提下,对其实现增强。

1
2
3
4
5
6
7
8
9
public class BlueGemEquipDecorator extends EquipDecorator {
public BlueGemEquipDecorator(Equip equip) {
super(equip);
}
@Override
public int mp() {
return equip.mp() + 10;
}
}

优点

  • 开闭原则: 不修改已有的类。
  • 组合优于继承:更灵活,可以无限叠加
  • 运行时可变: 可以在运行时添加或删除功能
  • 高内聚低耦合: 每个装饰器只关注自己的增强逻辑

装饰器模式与代理模式的区别

  1. 目的不同: 装饰器模式是作 增强功能;代理模式则是实现 控制访问
  2. 实现方式相同: 都是通过组合+接口一致性方式,都继承了目标的接口。
  3. 关注点不同: 装饰器模式是“添加职责”;代理模式是“封装访问“。
  4. 是否透明: 前者透明并增强;后者控制访问减少透明度