
本文介绍如何利用装饰器模式,在无法修改cow、pig等已有animal子类的情况下,通过pet类统一增强其行为(如重写droploot、扩展die逻辑),实现“运行时动态继承”效果。
本文介绍如何利用装饰器模式,在无法修改cow、pig等已有animal子类的情况下,通过pet类统一增强其行为(如重写droploot、扩展die逻辑),实现“运行时动态继承”效果。
在面向对象设计中,当需要为已存在的类层次结构动态添加职责,又受限于无法修改原始子类(如Cow、Pig)时,传统的继承(extends)和泛型类型参数化继承(如class Pet
装饰器模式的核心思想是:让一个类既继承目标抽象类型(实现“is-a”关系),又持有被装饰对象的引用(建立“has-a”关系),从而在不改变原有类的前提下,灵活地组合、覆盖或增强其行为。
以下为完整实现:
// 1. 抽象基类(保持不变)
public abstract class Animal {
public abstract void eat();
public abstract void ai();
public abstract void die();
public abstract void dropLoot();
}
// 2. 现有子类(禁止修改 —— Cow 和 Pig 均原样保留)
public class Cow extends Animal {
@Override public void eat() { System.out.println("Cow eats grass"); }
@Override public void ai() { System.out.println("Cow wanders aimlessly"); }
@Override public void die() { System.out.println("Cow collapses"); }
@Override public void dropLoot() { System.out.println("Cow drops leather and beef"); }
public void moo() { System.out.println("Moo!"); } // Cow特有方法,Pet无法访问(符合设计约束)
}
public class Pig extends Animal {
@Override public void eat() { System.out.println("Pig eats slop"); }
@Override public void ai() { System.out.println("Pig roots in mud"); }
@Override public void die() { System.out.println("Pig falls over"); }
@Override public void dropLoot() { System.out.println("Pig drops pork and hide"); }
}
// 3. 装饰器类:Pet —— 继承Animal,封装具体Animal实例
public class Pet extends Animal {
private final Animal decorated; // 持有被装饰对象(Cow/Pig实例)
public Pet(Animal animal) {
this.decorated = Objects.requireNonNull(animal, "Animal cannot be null");
}
// ✅ 选择性委托:ai() 完全交由底层实现
@Override
public void ai() {
decorated.ai();
}
// ✅ 扩展逻辑:die() 先执行宠物专属行为,再调用原逻辑
@Override
public void die() {
System.out.println("[Pet] Performing last rites...");
decorated.die(); // 调用Cow.die() 或 Pig.die()
System.out.println("[Pet] Pet spirit ascends ?");
}
// ✅ 完全覆盖:dropLoot() 替换原有行为,与Cow/Pig无关
@Override
public void dropLoot() {
System.out.println("[Pet] Drops heart-shaped loot & affection!");
}
// ✅ eat() 可选择增强(示例:加喂食动画)
@Override
public void eat() {
System.out.println("[Pet] Eating with joyful animation ✨");
decorated.eat();
}
}
✅ 使用方式简洁直观:
Animal petCow = new Pet(new Cow()); Animal petPig = new Pet(new Pig()); petCow.eat(); // [Pet] Eating with joyful animation ✨ → Cow eats grass petCow.ai(); // Cow wanders aimlessly petCow.die(); // [Pet] Performing last rites... → Cow collapses → [Pet] Pet spirit ascends ? petCow.dropLoot(); // [Pet] Drops heart-shaped loot & affection! // 同理适用于 pig,无需任何Cow/Pig代码变更
⚠️ 关键注意事项:
- Pet 不能访问 Cow.moo() 等子类特有方法——这正是设计所需:它仅作用于 Animal 接口契约,保障类型安全与可替换性;
- 所有委托调用需显式编写(如 decorated.ai()),无自动代理机制,但换来的是完全可控的行为定制;
- 若需多层装饰(如 Pet → TrainedPet → LegendaryPet),只需让每个装饰器继承 Animal 并包装前一层即可,天然支持组合;
- final Animal decorated 配合构造器注入,确保线程安全与不可变性,符合良好实践。
总结:当“想让Cow和Pig像Pet的子类一样工作”却无法修改它们时,不要强行突破Java语法限制(如幻想 extends T),而应拥抱设计模式的本质——用组合代替继承,用委托代替硬编码。装饰器模式不仅满足需求,更提升了系统可维护性与扩展性,是Java生态中久经考验的架构利器。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











