「层层包装」—— 装饰器模式

文章目录

示例代码

代码示例

完整代码

bash 复制代码
src/
├── common/                          # 共享接口包
│   └── Coffee.java                 # Component:组件接口
│
└── decorator/                      # 装饰器实现
    ├── SimpleCoffee.java          # Concrete Component:具体组件
    ├── CoffeeDecorator.java       # Base Decorator:基础装饰器
    ├── MilkDecorator.java         # Concrete Decorator:牛奶装饰器
    ├── SugarDecorator.java        # Concrete Decorator:糖装饰器
    ├── WhipDecorator.java         # Concrete Decorator:奶泡装饰器
    ├── CoffeeShopClient.java      # Client:客户端
    └── DecoratorDemo.java         # 运行入口

编译运行

bash 复制代码
# 编译
javac -d out src/common/*.java src/decorator/*.java

# 运行
java -cp out decorator.DecoratorDemo

什么是装饰器模式?

概念

装饰器模式 是一种结构型设计模式,它的核心作用是动态地给对象添加一些额外的职责。装饰器让对象可以在运行时扩展功能,而不需要修改原有的类。

简单来说,装饰器就是在包装

生活类比

就像咖啡店的点单系统:

  • 原味咖啡有基础价格和描述
  • 可以加牛奶(+5元)
  • 可以加糖(+2元)
  • 可以加奶泡(+8元)
  • 各种配料可以自由组合

在代码世界中,装饰器模式干的是同样的事:

  • 基础组件提供了核心功能
  • 装饰器可以在运行时包装组件,添加新功能
  • 多个装饰器可以层层嵌套,组合出不同的效果

装饰器模式中的四个角色

Component(组件接口)

被装饰对象的接口。在我们的例子中是 Coffee:

java 复制代码
// src/common/Coffee.java
package common;

public interface Coffee {
    int getCost();
    String getDescription();
}

客户端通过这个接口操作所有咖啡。

ConcreteComponent(具体组件)

实现组件接口的基础对象。在我们的例子中是 SimpleCoffee:

java 复制代码
// src/decorator/SimpleCoffee.java
package decorator;

import common.Coffee;

public class SimpleCoffee implements Coffee {
    @Override
    public int getCost() {
        return 10;
    }

    @Override
    public String getDescription() {
        return "原味咖啡";
    }
}

这是最基础的咖啡,不带任何配料。

Decorator(装饰器)

持有一个组件引用,并实现组件接口。装饰器本身也是组件,所以可以递归嵌套:

java 复制代码
// src/decorator/CoffeeDecorator.java
package decorator;

import common.Coffee;

public abstract class CoffeeDecorator implements Coffee {
    protected Coffee coffee;

    public CoffeeDecorator(Coffee coffee) {
        this.coffee = coffee;
    }

    @Override
    public int getCost() {
        return coffee.getCost();
    }

    @Override
    public String getDescription() {
        return coffee.getDescription();
    }
}

ConcreteDecorator(具体装饰器)

实际的装饰器实现,给组件添加新的行为:

java 复制代码
// src/decorator/MilkDecorator.java
package decorator;

import common.Coffee;

public class MilkDecorator extends CoffeeDecorator {
    public MilkDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public int getCost() {
        return super.getCost() + 5;
    }

    @Override
    public String getDescription() {
        return super.getDescription() + " + 牛奶";
    }
}

装饰器模式示例

结构图

bash 复制代码
客户端 --调用--> Coffee (Component)
                    ↑
                    |
                    | implements
            CoffeeDecorator (Decorator)
                    |
                    | 组合
                    ↓
            SimpleCoffee (ConcreteComponent)

运行示例

bash 复制代码
>>> 点一杯原味咖啡
  点单: 原味咖啡
  价格: ¥10

>>> 原味咖啡 + 牛奶
  点单: 原味咖啡 + 牛奶
  价格: ¥15

>>> 原味咖啡 + 牛奶 + 糖
  点单: 原味咖啡 + 牛奶 + 糖
  价格: ¥17

>>> 原味咖啡 + 牛奶 + 糖 + 奶泡
  点单: 原味咖啡 + 牛奶 + 糖 + 奶泡
  价格: ¥25

代码实现

java 复制代码
// 装饰器可以层层嵌套
Coffee coffee = new WhipDecorator(
    new SugarDecorator(
        new MilkDecorator(
            new SimpleCoffee()
        )
    )
);
coffee.getDescription(); // "原味咖啡 + 牛奶 + 糖 + 奶泡"
coffee.getCost();       // 25

装饰器模式 vs 继承

特性 继承 装饰器
扩展时机 编译时 运行时
组合灵活性 静态的,不易改变 动态可组合,任意组合
类数量 每种组合都需要一个新类 只需组件类 + 装饰器类
开闭原则 违反(修改现有类) 符合(扩展新功能无需修改现有类)

装饰器模式的优势

  1. 运行时扩展:可以在程序运行期间动态添加装饰
  2. 自由组合:多种配料可以任意组合,牛奶+糖+奶泡
  3. 开闭原则:对扩展开放,对修改封闭
  4. 单一职责:每个装饰器只关心自己添加的那部分功能
  5. 可复用性:装饰器之间相互独立,可单独复用

装饰器模式的注意事项

  1. 装饰器链不要太长:嵌套层次过多会导致调试困难
  2. 顺序敏感:不同的添加顺序会产生不同的结果
  3. 类型检查:需要注意被装饰对象的真实类型
相关推荐
小小张说故事1 小时前
Python 的 dict 为什么查询是 O(1)?拆开哈希表、扰动函数与扩容阈值
python
脏脏a1 小时前
延迟与画质:远程控制的生命线
开发语言·php
像风一样的男人@2 小时前
python --基于scp的文件传输助手
开发语言·python
一条破秋裤2 小时前
SDIO Wi‑Fi 设备的驱动向insmod + 反向rmmod
开发语言·php
m0_639906942 小时前
Java 重写 Override 与重载 Overload 区别、访问修饰符、static 关键字
java·开发语言
Evand J2 小时前
【MATLAB例程】平面下,5基站对待定位点的定位。基于距离辅助下的AOA。完整代码下载链接
开发语言·matlab·平面·定位·导航·测距·aoa
用户0332126663672 小时前
使用 Python 在 Word 文档中添加、修改和删除变量
python
GIS数据转换器2 小时前
基于CIM的城市智慧供热监管服务平台
java·大数据·开发语言·人工智能·后端·物联网·struts
专注仿真2 小时前
动态规划算法详解
人工智能·python·大模型训练·控制算法
weixin_417396832 小时前
星级酒店境外电视频道怎么合法接入?合规要点与核对清单
开发语言·前端·php·1024程序员节·综合布线