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原则:

  • 封装变化
  • 多用组合少用继承
  • 多用接口少用实现
  • 为交互对象之间的松耦合设计而努力
  • 对扩展开放,对修改关闭

装饰者模式——动态地将责任附加到对象上,想要扩展功能,装饰者提供有别于继承的另一种选择。

要点

  • 组合和委托可用于在运行时动态扩展我们行为
  • 装饰者模式意味着: 利用一群装饰者类来包装具体组件
  • 装饰者可以在被装饰者的行为前或后添加自己的行为,将被装饰者的行为整个取代掉达到特定目的
  • 装饰者会导致设计中出现许多小对象,如果过度使用使得程序变得复杂
posted @   Felix_Openmind  阅读(153)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
*{cursor: url(https://files-cdn.cnblogs.com/files/morango/fish-cursor.ico),auto;}
点击右上角即可分享
微信分享提示