装饰器模式详解(附代码案例和源码分析)

目录

装饰器模式的本质

装饰器模式和继承结构的对比

源码中IO流的继承结构

具体装饰器类

装饰器的组合应用

装饰器链的特点

代码案例

定义coffee类型

coffee的实现类

装饰器抽象类

[装饰器 - 季节限定](#装饰器 - 季节限定)

装饰器------加牛奶

装饰器------加糖

生成咖啡的简单工厂

咖啡制作服务(动态加功能)

装饰器模式的优点

装饰器模式的缺点


装饰器模式的本质

装饰器模式允许向一个现有的对象添加新的功能,同时又不改变其结构。它是一种用于代替继承的技术,通过组合的方式实现功能的扩展。这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。

多态与装饰器的结合优势,多态允许我们使用基类类型引用指向子类对象,这与装饰器模式完美契合。通过多态,我们可以在运行时动态决定使用哪些装饰器,而客户端代码无需关心具体实现细节。

装饰器模式和继承结构的对比

可能大家可能会有疑问,这装饰器功能不就和继承一样吗?为什么不直接用继承呢?还要装饰器模式有什么用?

现在可以想象一个场景,有一个coffee抽象类,下面有五个不同的coffee的实现类,若是我现在想给coffee类加上糖的功能,如果是用继承,那是不是要给这五个实现类都写子类实现。

如果过段时间,我又想添加一个新的功能呢?是不是又要给每个类写一个子类,这样的话会使这个继承结构变得非常冗杂。

那我现在做一个装饰器类,他的功能就是加糖,其中有个属性就是coffee抽象类,哪个coffee实现类想要有这个功能就直接赋值到装饰器类的属性就可以了,功能装饰器类都做了,那这样不就只用写一个类就好了?就避免了冗长的继承结构。

源码中IO流的继承结构

InputStream:字节输入流的抽象基类

OutputStream:字节输出流的抽象基类

FileInputStream:文件输入流,继承自InputStream

FileOutputStream:文件输出流,继承自OutputStream

ByteArrayInputStream:字节数组输入流,继承自InputStream

ByteArrayOutputStream:字节数组输出流,继承自OutputStream

FilterInputStream:过滤输入流,所有装饰器输入流的父类,持有一个InputStream引用,提供默认的装饰器实现

FilterOutputStream:过滤输出流,所有装饰器输出流的父类,持有一个OutputStream引用,提供默认的装饰器实现

具体装饰器类

BufferedInputStream:缓冲输入流,添加缓冲功能,提高读取效率,继承自FilterInputStream

BufferedOutputStream:缓冲输出流,添加缓冲功能,提高写入效率,继承自FilterOutputStream

DataInputStream:数据输入流,读取Java基本数据类型,支持基本类型的读取,继承自FilterInputStream

DataOutputStream:数据输出流,写入Java基本数据类型,支持基本类型的写入,继承自FilterOutputStream

装饰器的组合应用

基础流 + 缓冲:FileInputStream + BufferedInputStream

提供高效的文件读取

基础流 + 缓冲 + 数据类型处理:FileInputStream + BufferedInputStream + DataInputStream

装饰器链的特点

可以任意组合,每个装饰器,专注于一个功能,易于扩展新功能,优于继承的扩展方式

代码案例

定义coffee类型
java 复制代码
// 1. 定义咖啡类型
public enum CoffeeType {
    ESPRESSO, LATTE, MOCHA
}
java 复制代码
// 2. 扩展基础组件接口
public interface Coffee {
    String getDescription();
    double getCost();
    CoffeeType getType();
    void brew();  // 添加冲泡方法
}
coffee的实现类
java 复制代码
public class Espresso implements Coffee {
    @Override
    public String getDescription() {
        return "Espresso";
    }
    
    @Override
    public double getCost() {
        return 4.0;
    }
    
    @Override
    public CoffeeType getType() {
        return CoffeeType.ESPRESSO;
    }
    
    @Override
    public void brew() {
        System.out.println("Brewing strong espresso");
    }
}
java 复制代码
public class Latte implements Coffee {
    @Override
    public String getDescription() {
        return "Latte";
    }
    
    @Override
    public double getCost() {
        return 5.0;
    }
    
    @Override
    public CoffeeType getType() {
        return CoffeeType.LATTE;
    }
    
    @Override
    public void brew() {
        System.out.println("Brewing latte with steamed milk");
    }
}
装饰器抽象类
java 复制代码
public abstract class CoffeeDecorator implements Coffee {
    protected final Coffee decoratedCoffee;
    
    public CoffeeDecorator(Coffee coffee) {
        this.decoratedCoffee = coffee;
    }
    
    // 默认实现委托给被装饰对象
    @Override
    public String getDescription() {
        return decoratedCoffee.getDescription();
    }
    
    @Override
    public double getCost() {
        return decoratedCoffee.getCost();
    }
    
    @Override
    public CoffeeType getType() {
        return decoratedCoffee.getType();
    }
    
    @Override
    public void brew() {
        decoratedCoffee.brew();
    }
}
装饰器 - 季节限定
java 复制代码
public class SeasonalDecorator extends CoffeeDecorator {
    private final String season;
    
    public SeasonalDecorator(Coffee coffee, String season) {
        super(coffee);
        this.season = season;
    }
    
    @Override
    public void brew() {
        super.brew();
        addSeasonalTouch();
    }
    
    private void addSeasonalTouch() {
        switch(season.toLowerCase()) {
            case "summer":
                System.out.println("Adding ice and mint leaf");
                break;
            case "winter":
                System.out.println("Adding cinnamon and nutmeg");
                break;
        }
    }
}
装饰器------加牛奶
java 复制代码
public class MilkDecorator extends CoffeeDecorator {
    public MilkDecorator(Coffee coffee) {
        super(coffee);
    }
    
    @Override
    public String getDescription() {
        return decoratedCoffee.getDescription() + ", with Milk";
    }
    
    @Override
    public double getCost() {
        return decoratedCoffee.getCost() + 2.0;
    }
    
    // 特有方法
    public void addMilkFoam() {
        System.out.println("Adding milk foam");
    }
}
装饰器------加糖
java 复制代码
public class SugarDecorator extends CoffeeDecorator {
    public SugarDecorator(Coffee coffee) {
        super(coffee);
    }
    
    @Override
    public String getDescription() {
        return decoratedCoffee.getDescription() + ", with Sugar";
    }
    
    @Override
    public double getCost() {
        return decoratedCoffee.getCost() + 1.0;
    }
    
    // 特有方法
    public void mixSugar() {
        System.out.println("Mixing sugar thoroughly");
    }
}
生成咖啡的简单工厂
java 复制代码
public class CoffeeFactory {
    public static Coffee createCoffee(CoffeeType type) {
        switch(type) {
            case ESPRESSO:
                return new Espresso();
            case LATTE:
                return new Latte();
            case MOCHA:
                return new MochaDecorator(new Espresso());
            default:
                throw new IllegalArgumentException("Unknown coffee type");
        }
    }
}
咖啡制作服务(动态加功能)
java 复制代码
public class CoffeeService {
    public Coffee prepareCoffee(CoffeeType type, boolean withMilk, 
                              boolean withSugar, String season) {
        // 基础咖啡
        Coffee coffee = CoffeeFactory.createCoffee(type);
        
        // 根据条件动态添加装饰器
        if (withMilk) {
            coffee = new MilkDecorator(coffee);
        }
        
        if (withSugar) {
            coffee = new SugarDecorator(coffee);
        }
        
        // 季节性装饰
        if (season != null) {
            coffee = new SeasonalDecorator(coffee, season);
        }
        
        return coffee;
    }
    
    // 批量处理订单
    public List<Coffee> prepareOrders(List<CoffeeOrder> orders) {
        return orders.stream()
            .map(order -> prepareCoffee(
                order.getType(),
                order.isWithMilk(),
                order.isWithSugar(),
                order.getSeason()))
            .collect(Collectors.toList());
    }
}

通过多态,装饰器模式变得更加强大和灵活。它允许我们在运行时动态地组合不同的行为,同时保持代码的清晰和可维护性。这种组合为我们提供了一种优雅的方式来扩展对象的功能,而不需要创建大量的子类。

装饰器模式的优点

比继承更灵活:装饰类和被装饰类可以独立发展,不会相互耦合

动态扩展功能:通过组合不同的装饰器,可以实现不同的功能组合

符合开闭原则:增加新功能时,不需要修改原有代码,只需添加新的装饰类

具体组件类和装饰类可以独立变化:提供了比继承更多的灵活性

装饰器模式的缺点

会产生很多小对象:每个装饰器都要包装一个对象,会产生很多小对象

多层装饰比较复杂:如果层次过多,会使系统变得复杂

装饰器模式比继承更灵活,但也更容易出错,调试时寻找错误可能比较困难

相关推荐
大厂码农老A16 小时前
面试官:“聊聊你最复杂的项目?” 为什么90%的候选人第一句就栽了?
java·面试
爱读源码的大都督16 小时前
Java已死?别慌,看我如何用Java手写一个Qwen Code Agent,拯救Java
java·人工智能·后端
lssjzmn16 小时前
性能飙升!Spring异步流式响应终极指南:ResponseBodyEmitter实战与架构思考
java·前端·架构
LiuYaoheng16 小时前
【Android】View 的基础知识
android·java·笔记·学习
勇往直前plus16 小时前
Sentinel微服务保护
java·spring boot·微服务·sentinel
星辰大海的精灵16 小时前
SpringBoot与Quartz整合,实现订单自动取消功能
java·后端·算法
小鸡脚来咯16 小时前
一个Java的main方法在JVM中的执行流程
java·开发语言·jvm
江团1io016 小时前
深入解析三色标记算法
java·开发语言·jvm
天天摸鱼的java工程师16 小时前
RestTemplate 如何优化连接池?—— 八年 Java 开发的踩坑与优化指南
java·后端
你我约定有三16 小时前
java--泛型
java·开发语言·windows