设计模式之装饰器模式

一、介绍

装饰器模式(Decoration Pattern),属于结构型设计模式 ,用于在不改变现有对象 的基础上,对该对象的方法动态 地添加新的功能,实现对该对象原有方法的增强

装饰器模式的设计思想是将对象的核心功能 和附加功能独立开来。核心功能由现有对象提供,附加功能由装饰器提供。

装饰器的实现思路是存在一个抽象的装饰器类 ,该装饰器类用于对现有的对象进行包装,然后通过该装饰器的具体子类对包装的类的方法进行增强。推而论之,在存在多个装饰器具体子类的情况下,可以动态地对现有对象随心所欲进行嵌套包装,对现有对象进行包装后,可以在已包装基础上进行多层嵌套包装

二、主要角色

在装饰器模式中,主要包含以下四个角色:

  • 核心组件抽象接口(Component)

规定了被装饰对象的行为。

  • 核心组件具体实现(ComponentImpl)

实现核心组件抽象接口,对接口规定的行为进行具体实现。

  • 抽象装饰器(AbsDecoration)

通用的装饰ComponentImpl的装饰器,该装饰器必须包含一个以被装饰对象为参数的构造方法。

该装饰器设定为抽象类的原因是通过其构造函数管理被装饰的对象,以此来限制具体装饰器的构造方法必须传入被装饰的对象。

  • 具体装饰器(Decoration)

继承抽象装饰器。用于增强对被装饰对象某一功能的特定装饰逻辑

三、案例

核心组件抽象接口

复制代码
public interface Coffee {
    /**
     * 获取描述信息
     */
    String getDescription();

    /**
     * 获取花费
     */
    double getCost();
}

核心组件具体实现

黑咖啡 就是核心

java 复制代码
public class BlackCoffee implements Coffee{
    @Override
    public String getDescription() {
        return "黑咖啡";
    }

    @Override
    public double getCost() {
        return 10;
    }
}

抽象装饰器

java 复制代码
public abstract class CoffeeDecorator implements Coffee {
    protected Coffee coffee;

    public CoffeeDecorator(Coffee coffee) {
        this.coffee = coffee;
    }
    @Override
    public String getDescription() {
        return coffee.getDescription();
    }

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

具体装饰器

给咖啡加牛奶

java 复制代码
public class MilkDecorator extends CoffeeDecorator {
    public MilkDecorator(Coffee coffee) {
        super(coffee);
    }

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

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

}

给咖啡加糖

java 复制代码
public class SugarDecorator extends CoffeeDecorator{
    public SugarDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String getDescription() {
        return super.getDescription() + ", 加糖";
    }

    @Override
    public double getCost() {
        return super.getCost() + 2;
    }
}

测试

在存在多个装饰器具体子类的情况下,可以动态地对现有对象随心所欲进行嵌套包装

上面的例子也可以加2分牛牛奶一份糖,可以随心所欲的进行装饰。

四、装饰器模式在jdk的应用

java中的IO是明显的装饰器模式的运用。FilterInputStream,FilterOutputStream,FilterRead,FilterWriter分别为具体装饰器的父类,相当于Decorator类,它们分别实现了InputStream,OutputStream,Reader,Writer类(这些类相当于Component,是其他组件类的父类,也是Decorator类的父类)。

继承自InputStream,OutputStream,Reader,Writer这四个类的其他类是具体的组件类,每个都有相应的功能,相当于ConcreteComponent类。而继承自FilterInputStream,FilterOutputStream,FilterRead,FilterWriter这四个类的其他类就是具体的装饰器对象类,即ConcreteDecorator类。通过这些装饰器类,可以给我们提供更加具体的有用的功能。如FileInputStream是InputStream的一个子类,从文件中读取数据流,BufferedInputStream是继承自FilterInputStream的具体的装饰器类,该类提供一个内存的缓冲区类保存输入流中的数据。我们使用如下的代码来使用BufferedInputStream装饰FileInputStream,就可以提供一个内存缓冲区来保存从文件中读取的输入流

①组件接口,相当于Component:

InputStream

OutputStream

Reader

Writer

②组件的实现类,相当于ConcreteComponent

FileInputStream

③装饰器接口,相当于Decorator

FilterInputStream

FilterOutputStream

FilterRead

FilterWriter

④装饰器类

BufferedInputStream继承自FilterInputStream

使用说明:我们可以用BufferedInputStream修饰FileInputStream

例如

java 复制代码
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file)); 
//其中file为某个具体文件的File或者FileDescription对象
java 复制代码
FileWriter file = new FileWriter("sample.txt");
BufferedWriter writer = new BufferedWriter(file);
writer.write("a small amount of sample text");
writer.newLine();
writer.close();

五、优缺点

优点:

由于装饰器对象和被装饰的对象都实现于核心抽象接口,根据面向接口编程原则,它们具有相同的行为。

装饰器不仅可以将已有对象进行包装,也可以对装饰器对象嵌套包装。

通过使用不同装饰类以及这些装饰类的排列组合,可以实现不同效果。

避免多个被装饰对象与装饰器而导致最终类数量上的膨胀。
缺点:

每当为被装饰对象添加新的功能,都需要为其新建一个装饰类

六、适用场景

动态功能扩展: 运行时为对象添加或移除功能(如日志、缓存、加密)
避免多层继承: 替代复杂的继承树(如 BufferedFileReader、EncryptedFileReader)
透明性要求: 客户端无需感知对象是否被装饰(保持接口一致性)。
功能组合复用: 支持多种功能的自由组合(如 压缩 + 加密 文件流)

相关推荐
tongyiixiaohuang16 分钟前
供应商主数据同步实战:从易快报到金蝶云星空的单一策略落地
java·网络·数据库
鱼宵1 小时前
取集合第一个元素,Java 为什么要写三种写法?
java·windows·python·java21
学长毕设1 小时前
基于SpringBoot的餐厅管理系统-附源码
java·spring boot·后端
刚入门的大一新生1 小时前
Linux-线程互斥
java·开发语言
赵小哥要冲啦2 小时前
社区邻里互助小程序从 0 到 1 复盘:需求拆解与信任机制设计
java·小程序·需求分析
xiaogai_gai2 小时前
采购业务退款单同步实战:从钉钉审批流到金蝶云星空付款单
java·数据库·钉钉
二哈赛车手2 小时前
新人笔记---hermes定时功能设计,具体讲解以及可优化点
java·人工智能·笔记·spring·ai·typescript
ZWZhangYu2 小时前
从 Dify 实践理解大模型上下文缓存
java·后端·spring
小羊没烦恼!3 小时前
关于分布式锁原理的一些学习与思考-redis分布式锁,zookeeper分布式锁
java·服务器·网络·学习·负载均衡
Fuyo_11194 小时前
C++ AVL树保姆级详解:从平衡因子到四大旋转机制
java·c++·算法