当前位置: 首页 > article >正文

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

目录

装饰器模式的本质

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

源码中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类型
// 1. 定义咖啡类型
public enum CoffeeType {
    ESPRESSO, LATTE, MOCHA
}
// 2. 扩展基础组件接口
public interface Coffee {
    String getDescription();
    double getCost();
    CoffeeType getType();
    void brew();  // 添加冲泡方法
}
coffee的实现类 
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");
    }
}
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");
    }
}
装饰器抽象类
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();
    }
}
装饰器 - 季节限定
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;
        }
    }
}
装饰器——加牛奶 
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");
    }
}
装饰器——加糖 
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");
    }
}

 

生成咖啡的简单工厂
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");
        }
    }
}
咖啡制作服务(动态加功能)
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());
    }
}

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

装饰器模式的优点

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

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

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

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

装饰器模式的缺点

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

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

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


http://www.kler.cn/a/506603.html

相关文章:

  • 内存与缓存:保姆级图文详解
  • 【大数据】机器学习-----模型的评估方法
  • 运行fastGPT 第四步 配置ONE API 添加模型
  • Django框架:python web开发
  • 基于Linux系统指令使用详细解析
  • DAMA CDGA 备考笔记(二)
  • phaserjs+typescript游戏开发之camera实现
  • SQL正则表达式用法大全以及如何利用正则表达式处理复杂数据
  • DCU异构程序--矩阵乘
  • mysql zabbix监控方法
  • JAVA:责任链模式(Chain of Responsibility Pattern)的技术指南
  • 基于springboot的rmi远程调用
  • API调用过程中遇到错误的解决方案
  • 清除前端缓存的方式
  • OpenCV相机标定与3D重建(54)解决透视 n 点问题(Perspective-n-Point, PnP)函数solvePnP()的使用
  • python助力WRF自动化运行
  • JavaEE之常见的锁策略
  • Linux 音视频入门到实战专栏(音频篇)基于alsa api的音频播放/录制流程
  • 2024年细讲前端工程化 万字总结!!
  • D3.js及实例应用
  • Apache搭建https服务器
  • Windows上安装和配置Tabby终端工具并实现远程ssh连接内网服务器
  • C#中字符串方法
  • react native学习【6.1】——列表视图
  • 【Qt】03-页面切换
  • MyBatis映射文件SQL深入(动态SQL)