Java 设计模式西游篇 - 第五回:装饰者模式添法力 悟空披挂新战袍

诗曰:

复制代码
法宝威力需增强,继承子类太繁琐。
装饰者模式来相助,动态添法显神通。

📖 故事

话说师徒四人来到"法力增强山",悟空觉得金箍棒威力不够,想要增强法力。

悟空愁道:"师父,这山的妖怪厉害,俺老孙的金箍棒威力不够啊!"

唐僧道:"悟空,你可有法子增强法力?"

悟空挠头:"徒儿倒是想过,要么打造一把新棒子,要么给金箍棒附魔。可要是每种附魔都要打造新棒子,那不得累死俺老孙!"

🐉 踩坑打怪:继承爆炸之劫

第一劫:类爆炸

悟空想了个笨办法:

java 复制代码
// 基础金箍棒
public class GoldenCudgel {
    public void attack() {
        System.out.println("金箍棒 - 普通攻击!");
    }
}

// 火焰金箍棒
public class FireGoldenCudgel extends GoldenCudgel {
    @Override
    public void attack() {
        super.attack();
        System.out.println("附加火焰伤害!");
    }
}

// 冰冻金箍棒
public class IceGoldenCudgel extends GoldenCudgel {
    @Override
    public void attack() {
        super.attack();
        System.out.println("附加冰冻伤害!");
    }
}

// 雷电金箍棒
public class ThunderGoldenCudgel extends GoldenCudgel {
    @Override
    public void attack() {
        super.attack();
        System.out.println("附加雷电伤害!");
    }
}

// 火焰 + 冰冻金箍棒
public class FireIceGoldenCudgel extends GoldenCudgel {
    @Override
    public void attack() {
        super.attack();
        System.out.println("附加火焰伤害!");
        System.out.println("附加冰冻伤害!");
    }
}

// 火焰 + 雷电金箍棒...
// 冰冻 + 雷电金箍棒...
// 火焰 + 冰冻 + 雷电金箍棒...

八戒惊呼: "猴哥!你这得有几十种组合啊!每加一种附魔,就要多好几个类!"

悟空怒道: "正是!这'继承爆炸'太坑了!俺老孙得想个巧法子!"

⚔️ 装饰者模式大法

第一步:定义组件接口
java 复制代码
// 武器接口
public interface Weapon {
    void attack();
    int getDamage();
}
第二步:实现具体组件
java 复制代码
// 基础金箍棒
public class GoldenCudgel implements Weapon {
    @Override
    public void attack() {
        System.out.println("金箍棒 - 普通攻击!");
    }
    
    @Override
    public int getDamage() {
        return 100;
    }
}
第三步:实现装饰者基类
java 复制代码
// 装饰者基类
public abstract class WeaponDecorator implements Weapon {
    protected Weapon weapon; // 持有一个武器引用
    
    public WeaponDecorator(Weapon weapon) {
        this.weapon = weapon;
    }
    
    @Override
    public void attack() {
        weapon.attack(); // 委托给被装饰的武器
    }
    
    @Override
    public int getDamage() {
        return weapon.getDamage();
    }
}
第四步:实现具体装饰者
java 复制代码
// 火焰附魔装饰者
public class FireEnchantDecorator extends WeaponDecorator {
    public FireEnchantDecorator(Weapon weapon) {
        super(weapon);
    }
    
    @Override
    public void attack() {
        weapon.attack();
        System.out.println("附加火焰伤害!🔥");
    }
    
    @Override
    public int getDamage() {
        return weapon.getDamage() + 20;
    }
}

// 冰冻附魔装饰者
public class IceEnchantDecorator extends WeaponDecorator {
    public IceEnchantDecorator(Weapon weapon) {
        super(weapon);
    }
    
    @Override
    public void attack() {
        weapon.attack();
        System.out.println("附加冰冻伤害!❄️");
    }
    
    @Override
    public int getDamage() {
        return weapon.getDamage() + 15;
    }
}

// 雷电附魔装饰者
public class ThunderEnchantDecorator extends WeaponDecorator {
    public ThunderEnchantDecorator(Weapon weapon) {
        super(weapon);
    }
    
    @Override
    public void attack() {
        weapon.attack();
        System.out.println("附加雷电伤害!⚡");
    }
    
    @Override
    public int getDamage() {
        return weapon.getDamage() + 25;
    }
}

// 吸血附魔装饰者
public class LifestealDecorator extends WeaponDecorator {
    public LifestealDecorator(Weapon weapon) {
        super(weapon);
    }
    
    @Override
    public void attack() {
        weapon.attack();
        System.out.println("附加吸血效果!🩸");
    }
    
    @Override
    public int getDamage() {
        return weapon.getDamage() + 10;
    }
}
第五步:实战演练
java 复制代码
public class Main {
    public static void main(String[] args) {
        // 基础金箍棒
        Weapon cudgel = new GoldenCudgel();
        System.out.println("=== 基础金箍棒 ===");
        cudgel.attack();
        System.out.println("伤害:" + cudgel.getDamage());
        
        // 火焰金箍棒
        System.out.println("\n=== 火焰金箍棒 ===");
        Weapon fireCudgel = new FireEnchantDecorator(new GoldenCudgel());
        fireCudgel.attack();
        System.out.println("伤害:" + fireCudgel.getDamage());
        
        // 火焰 + 冰冻金箍棒
        System.out.println("\n=== 火焰 + 冰冻金箍棒 ===");
        Weapon fireIceCudgel = new IceEnchantDecorator(
            new FireEnchantDecorator(new GoldenCudgel())
        );
        fireIceCudgel.attack();
        System.out.println("伤害:" + fireIceCudgel.getDamage());
        
        // 火焰 + 冰冻 + 雷电金箍棒
        System.out.println("\n=== 火焰 + 冰冻 + 雷电金箍棒 ===");
        Weapon ultimateCudgel = new ThunderEnchantDecorator(
            new IceEnchantDecorator(
                new FireEnchantDecorator(new GoldenCudgel())
            )
        );
        ultimateCudgel.attack();
        System.out.println("伤害:" + ultimateCudgel.getDamage());
        
        // 终极形态:全附魔 + 吸血
        System.out.println("\n=== 终极形态:全附魔 + 吸血 ===");
        Weapon godCudgel = new LifestealDecorator(
            new ThunderEnchantDecorator(
                new IceEnchantDecorator(
                    new FireEnchantDecorator(new GoldenCudgel())
                )
            )
        );
        godCudgel.attack();
        System.out.println("伤害:" + godCudgel.getDamage());
    }
}

输出:

复制代码
=== 基础金箍棒 ===
金箍棒 - 普通攻击!
伤害:100

=== 火焰金箍棒 ===
金箍棒 - 普通攻击!
附加火焰伤害!🔥
伤害:120

=== 火焰 + 冰冻金箍棒 ===
金箍棒 - 普通攻击!
附加火焰伤害!🔥
附加冰冻伤害!❄️
伤害:135

=== 火焰 + 冰冻 + 雷电金箍棒 ===
金箍棒 - 普通攻击!
附加火焰伤害!🔥
附加冰冻伤害!❄️
附加雷电伤害!⚡
伤害:160

=== 终极形态:全附魔 + 吸血 ===
金箍棒 - 普通攻击!
附加火焰伤害!🔥
附加冰冻伤害!❄️
附加雷电伤害!⚡
附加吸血效果!🩸
伤害:170

🏆 战斗总结

悟空得意: "哈哈!俺老孙这装饰者模式,想加什么附魔就加什么,不用打造新棒子!"

八戒问: "猴哥,这和继承有啥区别?"

悟空答: "呆子,听好了------"

对比项 继承 装饰者模式
类数量 组合爆炸 线性增长
灵活性 编译时固定 运行时动态组合
扩展性 改代码 加新装饰者
职责 容易混杂 单一职责

本章要点

要点 说明
核心思想 动态地给对象添加职责,继承的替代方案
适用场景 需要动态添加功能、避免类爆炸
优点 灵活组合、符合开闭原则、单一职责
缺点 装饰者过多会增加复杂度、调试困难

下回预告

话说师徒继续西行,来到"真假美猴王岭"。两个悟空一模一样,如何辨别?且看代理模式如何设关卡!

欲知后事如何,且听第六回分解!


相关推荐
程序员JerrySUN1 天前
别再把 HTTPS 和 OTA 看成两回事:一篇讲透 HTTPS 协议、安全通信机制与 Mender 升级加密链路的完整文章
android·java·开发语言·深度学习·流程图
郝学胜-神的一滴1 天前
系统设计与面向对象设计:两大设计思想的深度剖析
java·前端·c++·ue5·软件工程
myloveasuka1 天前
[Java]子类到底能继承父类中的哪些东西?继承中成员变量/方法访问特点---就近原则
java·开发语言
umeelove351 天前
vscode配置django环境并创建django项目(全图文操作)
java
x-cmd1 天前
[260307] x-cmd v0.8.6:新增 gpt-5.4 模型支持,sudo/os/hostname/cpu 等模块文档更新
java·数据库·gpt·sudo·x-cmd·googel
PPPPickup1 天前
深信服公司---java实习生后端一二面询问
java·后端·ai
架构师沉默1 天前
为什么很多大厂 API 不再使用 PUT 和 DELETE?
java·后端·架构
YDS8291 天前
SpringCloud —— Elasticsearch的DSL查询
java·elasticsearch·搜索引擎·spring cloud
亚马逊云开发者1 天前
你的 AI Agent 在裸奔吗?四层防护方案,从权限到审计一次讲透
java
意疏1 天前
openJiuwen实战:用AsyncCallbackFramework为Agent增强器添加可观测性
java·服务器·前端