Decorator Pattern(装饰者模式)
装饰者模式在不修改底层代码的情况下动态赋予对象新的责任。
解决什么问题?
- 动态增加功能,动态撤销。
- 扩展一个类的功能。
使用子类将不同的子类以不同的方式扩展类,但扩展是在编译时绑定到该类,不会在运行时更改;
模式的结构-类图
装饰模式主要包含以下角色。
抽象构件(Component)角色:定义一个抽象接口以规范准备接收附加责任的对象。
具体构件(Concrete Component)角色:实现抽象构件,通过装饰角色为其添加一些职责。
抽象装饰(Decorator)角色:继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
具体装饰(ConcreteDecorator)角色:实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。
此模式为了使多个装饰器可以批次堆叠,每次向覆盖的方法添加新功能。
装饰者和原始类对象共享一组公共功能,无论是装饰版本还是未装饰版本都是可以使用公共方法(图中:methodA()和methodB())方法。
装饰特征(eg:方法、属性或其他成员)通常由装饰器和装饰对象共享的接口。
装饰者模式是子类的替代方案,子类会在编译时添加行为,并改变原始类的所有实例;装饰可以在运行时为所选对象提供新的行为。
实例代码01
类图
模仿CF中神器子弹加成功能
/** * 组件抽象类 * */ abstract class BulletSys{ int numBullets; public abstract int getNumBullets(); } /** * 组件实现类 * */ class AK47_Bullect extends BulletSys{ public AK47_Bullect(){ super.numBullets = 30;// 默认AK47的子弹30发 } @Override public int getNumBullets() { return this.numBullets; } } /** * 模拟buff加成规则 * */ enum Weapon_BuffAdd{ AK47_麒麟(5), AK47_火麒麟(6), AK47_无影(7), AK47_黑武士(8); private int bulletsAddNums; // 子弹加成数(子弹增量) Weapon_BuffAdd(int _bulletsAddNums){ this.bulletsAddNums = _bulletsAddNums; } public int getBulletsAddNums() { return this.bulletsAddNums; } } // 装饰者抽象类 abstract class BulletBuff extends BulletSys{ public abstract int getNumBullets(); } /** * 装饰者实现类 */ class AK47_BulletBuff extends BulletBuff { private BulletSys bulletSys; public AK47_BulletBuff(BulletSys _BulletSys, String weapon_name){ this.bulletSys = _BulletSys; for(Weapon_BuffAdd ak47_buffAdd : Weapon_BuffAdd.values()){ if(weapon_name.equals(ak47_buffAdd.name())){ this.bulletSys.numBullets += ak47_buffAdd.getBulletsAddNums(); } } } @Override public int getNumBullets() { return this.bulletSys.getNumBullets(); } } public class TestDemo { public static void main(String[] args) { BulletSys bulletSys = new AK47_Bullect(); System.out.println("平民玩家的AK47子弹数: " + bulletSys.getNumBullets()); System.out.println("==========================="); System.out.println("氪金玩家通过购买神器进行子弹加成"); AK47_BulletBuff ak47_bulletBuff = new AK47_BulletBuff(bulletSys, "AK47_火麒麟"); System.out.println("氪金玩家的AK47子弹数:" + bulletSys.getNumBullets()); } } 输出 平民玩家的AK47子弹数: 30 =========================== 氪金玩家通过购买神器进行子弹加成 氪金玩家的AK47子弹数:36
实例代码02
类图
咖啡☕️制作功能实现
/** * The interface Coffee defines the functionality of Coffee implemented by decorator * */ interface Coffee{ public double getCost(); // Returns the cost of the coffee public String getIngredients(); // Returns the ingredients of the coffee } /** * Extension of a simple coffee without any extra ingredients * */ class SimpleCoffee implements Coffee{ @Override public double getCost() { return 1; } @Override public String getIngredients() { return "Coffee"; } } /** * Abstract decorator class - note that it implements Coffee interface * */ abstract class CoffeeDecorator implements Coffee{ private final Coffee decoratedCoffee; public CoffeeDecorator(Coffee c){ this.decoratedCoffee = c; } @Override public double getCost(){ // Implementing methods of the interface return decoratedCoffee.getCost(); } @Override public String getIngredients(){ return decoratedCoffee.getIngredients(); } } /** * Decorator WithMilk mixes milk into coffee. * Note it extends CoffeeDecorator * */ class WithMilk extends CoffeeDecorator{ public WithMilk(Coffee c) { super(c); } @Override public double getCost() { // Overriding methods defined in the abstract superclass return super.getCost() + 0.5; } @Override public String getIngredients() { return super.getIngredients() + ", Milk"; } } /** * Decorator WithSprinkles mixes sprinkles onto coffee. * Note it extends CoffeeDecorator * */ class WithSprinkles extends CoffeeDecorator{ public WithSprinkles(Coffee coffee){ super(coffee); } @Override public double getCost() { return super.getCost() + 0.6; } @Override public String getIngredients() { return super.getIngredients() + ", Sprinkles"; } } public class DemoSpace02 { public static void printInfo(Coffee c){ System.out.println("Cost: " + c.getCost() + "; Ingredients: " + c.getIngredients()); } public static void main(String[] args) { Coffee coffee = new SimpleCoffee(); printInfo(coffee); coffee = new WithMilk(coffee); printInfo(coffee); coffee = new WithSprinkles(coffee); printInfo(coffee); } } // 输出 Cost: 1.0; Ingredients: Coffee Cost: 1.5; Ingredients: Coffee, Milk Cost: 2.1; Ingredients: Coffee, Milk, Sprinkles
总结
OO原则:
- 封装变化
- 多用组合少用继承
- 多用接口少用实现
- 为交互对象之间的松耦合设计而努力
- 对扩展开放,对修改关闭
装饰者模式——动态地将责任附加到对象上,想要扩展功能,装饰者提供有别于继承的另一种选择。
要点
- 组合和委托可用于在运行时动态扩展我们行为
- 装饰者模式意味着: 利用一群装饰者类来包装具体组件
- 装饰者可以在被装饰者的行为前或后添加自己的行为,将被装饰者的行为整个取代掉达到特定目的
- 装饰者会导致设计中出现许多小对象,如果过度使用使得程序变得复杂
学而不思则罔,思而不学则殆!
分类:
设计模式
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具