若要扩展功能,装饰者提供了比集成更有弹性的替代方案,动态地将责任附加到对象上。
核心结构
装饰器模式(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 "🗡"; } }
|
实现其装饰器,可以为interface
或abstract
,
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; } }
|
优点:
- 开闭原则: 不修改已有的类。
- 组合优于继承:更灵活,可以无限叠加
- 运行时可变: 可以在运行时添加或删除功能
- 高内聚低耦合: 每个装饰器只关注自己的增强逻辑
装饰器模式与代理模式的区别
- 目的不同: 装饰器模式是作 增强功能;代理模式则是实现 控制访问。
- 实现方式相同: 都是通过组合+接口一致性方式,都继承了目标的接口。
- 关注点不同: 装饰器模式是“添加职责”;代理模式是“封装访问“。
- 是否透明: 前者透明并增强;后者控制访问减少透明度