【设计模式】装饰器模式(结构型)⭐⭐

文章目录

  • 1.概念
    • [1.1 什么是装饰器模式](#1.1 什么是装饰器模式)
    • [1.2 优点与缺点](#1.2 优点与缺点)
  • 2.实现方式
  • [3. Java 哪些地方用到了装饰器模式](#3. Java 哪些地方用到了装饰器模式)
  • [4. Spring 哪些地方用到了装饰器模式](#4. Spring 哪些地方用到了装饰器模式)

1.概念

1.1 什么是装饰器模式

它允许用户在不修改现有对象的代码的情况下向对象添加新的功能;这种模式是通过创建一个包含该对象的包装对象来实现的,从而扩展该对象的功能。

1.2 优点与缺点

优点 :

1.灵活性和扩展性:装饰器模式允许在运行时向对象添加新的行为,提供了比继承更大的灵活性。

2.遵守开闭原则:装饰器模式允许向系统添加新的行为而不需要修改现有代码,这符合开闭原则(软件实体应该对扩展开放,对修改关闭)。

3.代码复用:装饰器可以被多个对象共享,这减少了代码的重复,提高了代码复用性。

4.对象功能增强:在不改变原有对象的情况下,可以有选择性地增强对象的功能。

5.组合优于继承:装饰器模式使用对象组合而不是继承来扩展功能,这有助于避免继承层次可能带来的复杂性和脆弱性。
缺点 :

1.增加复杂性:装饰器模式可能会增加系统的复杂性,因为需要创建多个小对象来表示不同的功能。2.调试困难:由于装饰器可以嵌套使用,调试和理解运行时的行为可能会变得更加困难。

3.性能问题:装饰器模式可能会引入额外的性能开销,因为需要创建额外的对象,并且可能需要通过多个装饰器来解析方法调用。

4.设计复杂:如果使用不当,装饰器模式可能会导致设计变得复杂,特别是当装饰器之间的关系变得复杂时。

5.接口限制:装饰器模式要求装饰器和被装饰的对象实现相同的接口,这在某些情况下可能是不切实际的。

2.实现方式

①定义接口

java 复制代码
public interface Beverage {
    String getDescription();
    double cost();
}

②创建一个实现了Beverage接口的具体类SimpleCoffee

java 复制代码
public class SimpleCoffee implements Beverage {
    @Override
    public String getDescription() {
        return "Simple Coffee";
    }

    @Override
    public double cost() {
        return 1.0;
    }
}

③定义一个装饰器类CondimentDecorator,它也实现了Beverage接口,并持有一个Beverage对象的引用:

java 复制代码
public abstract class CondimentDecorator implements Beverage {
    protected Beverage beverage;

    public CondimentDecorator(Beverage beverage) {
        this.beverage = beverage;
    }

    public abstract String getDescription();
}

④创建具体的装饰器类,比如Milk、Sugar和Chocolate,它们都扩展了CondimentDecorator并添加了各自的成本和描述:

java 复制代码
public class Milk extends CondimentDecorator {
    public Milk(Beverage beverage) {
        super(beverage);
    }

    @Override
    public String getDescription() {
        return beverage.getDescription() + ", Milk";
    }

    @Override
    public double cost() {
        return beverage.cost() + 0.5;
    }
}

public class Sugar extends CondimentDecorator {
    public Sugar(Beverage beverage) {
        super(beverage);
    }

    @Override
    public String getDescription() {
        return beverage.getDescription() + ", Sugar";
    }

    @Override
    public double cost() {
        return beverage.cost() + 0.1;
    }
}

public class Chocolate extends CondimentDecorator {
    public Chocolate(Beverage beverage) {
        super(beverage);
    }

    @Override
    public String getDescription() {
        return beverage.getDescription() + ", Chocolate";
    }

    @Override
    public double cost() {
        return beverage.cost() + 0.3;
    }
}

⑤ 使用

java 复制代码
public class DecoratorDemo {
    public static void main(String[] args) {
        Beverage coffee = new SimpleCoffee();
        System.out.println(coffee.getDescription() + " $" + coffee.cost());

        coffee = new Milk(coffee);
        coffee = new Sugar(coffee);
        coffee = new Chocolate(coffee);

        System.out.println(coffee.getDescription() + " $" + coffee.cost());
    }
}

3. Java 哪些地方用到了装饰器模式

Java I/O 流

Java的I/O库广泛使用了装饰器模式来增强基本输入输出流的功能。例如,BufferedInputStream和BufferedOutputStream类通过装饰基本的InputStream和OutputStream来提供缓冲功能。同样,DataInputStream和DataOutputStream为基本的流添加了读写基本数据类型的能力。
Java Servlet API

Java Servlet API中的HttpServletRequestWrapper和HttpServletResponseWrapper类允许开发者通过装饰原始的HttpServletRequest和HttpServletResponse对象来添加或修改功能。
Java动态代理

Java的动态代理机制允许在运行时创建一个实现了一组接口的代理类实例。这个代理实例实际上是一个装饰器,它可以在不修改原始对象代码的情况下,为原始对象添加新的行为,如事务管理、日志记录等。
Spring框架

Spring框架在很多地方使用了装饰器模式,例如在AOP(面向切面编程)中,Spring会创建代理对象来包装目标对象,以实现事务管理、权限检查等横切关注点的功能。
Apache Commons IO

Apache Commons IO库提供了一些装饰器类,如ProxyInputStream和ProxyOutputStream,这些类可以用来创建自定义的流装饰器。
JDBC

JDBC驱动程序有时会使用装饰器模式来增强或修改原始的Connection、Statement或ResultSet对象的行为。
JAX-RS

JAX-RS(Java API for RESTful Web Services)中的客户端API允许使用装饰器模式来增强或修改Client、WebTarget、Invocation等对象的行为。

4. Spring 哪些地方用到了装饰器模式

AOP (面向切面编程):

Spring AOP允许通过声明式方式添加横切关注点(如日志记录、事务管理、安全检查等)到目标对象。Spring创建代理对象来包装目标对象,这些代理对象在调用目标方法前后执行额外的代码。这实际上是一种装饰器模式的应用,它允许在不修改目标对象代码的情况下增强其行为。
事务管理

在Spring中,事务管理通常是通过AOP实现的。Spring可以为目标方法创建一个代理,该代理在方法执行前后管理事务的开启和关闭,而无需修改目标方法的代码。
Spring Security

Spring Security使用方法拦截器来实现安全控制。它可以为目标方法创建代理,这些代理在方法执行前检查用户的权限,如果用户没有足够的权限,则不允许执行目标方法。
Spring Data JPA

Spring Data JPA中的仓库(Repository)可以通过自定义的实现来扩展。开发者可以创建一个自定义的仓库实现,并通过Spring的配置将其与标准仓库接口关联起来。这实际上是在使用装饰器模式来扩展仓库的功能。
Spring WebFlux

Spring WebFlux中的WebFilter和WebExceptionHandler可以被视为装饰器模式的应用。它们允许在请求处理的各个阶段添加额外的处理逻辑,而不需要修改原始的处理器代码。
Spring Cloud

在Spring Cloud中,装饰器模式被用于实现服务断路器、负载均衡等功能。例如,Hystrix断路器可以通过装饰原始的服务调用逻辑来添加断路器功能,从而在服务调用失败时提供备选方案。
Spring Boot

Spring Boot自动配置的原理也可以看作是装饰器模式的一种应用。Spring Boot可以自动配置各种组件,如数据源、事务管理器等,这些自动配置的组件可以被用户的自定义配置所增强或覆盖。

相关推荐
喵叔哟12 分钟前
重构代码中引入外部方法和引入本地扩展的区别
java·开发语言·重构
尘浮生18 分钟前
Java项目实战II基于微信小程序的电影院买票选座系统(开发文档+数据库+源码)
java·开发语言·数据库·微信小程序·小程序·maven·intellij-idea
闲人一枚(学习中)25 分钟前
设计模式-创建型-抽象工厂模式
设计模式·抽象工厂模式
行則独善其身33 分钟前
计算机网络-VPN虚拟专用网络概述
程序人生
不是二师兄的八戒42 分钟前
本地 PHP 和 Java 开发环境 Docker 化与配置开机自启
java·docker·php
爱编程的小生1 小时前
Easyexcel(2-文件读取)
java·excel
带多刺的玫瑰1 小时前
Leecode刷题C语言之统计不是特殊数字的数字数量
java·c语言·算法
计算机毕设指导62 小时前
基于 SpringBoot 的作业管理系统【附源码】
java·vue.js·spring boot·后端·mysql·spring·intellij-idea
Gu Gu Study2 小时前
枚举与lambda表达式,枚举实现单例模式为什么是安全的,lambda表达式与函数式接口的小九九~
java·开发语言
Chris _data2 小时前
二叉树oj题解析
java·数据结构