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

文章目录

  • 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可以自动配置各种组件,如数据源、事务管理器等,这些自动配置的组件可以被用户的自定义配置所增强或覆盖。

相关推荐
腥臭腐朽的日子熠熠生辉21 分钟前
解决maven失效问题(现象:maven中只有jdk的工具包,没有springboot的包)
java·spring boot·maven
ejinxian23 分钟前
Spring AI Alibaba 快速开发生成式 Java AI 应用
java·人工智能·spring
杉之28 分钟前
SpringBlade 数据库字段的自动填充
java·笔记·学习·spring·tomcat
圈圈编码1 小时前
Spring Task 定时任务
java·前端·spring
俏布斯1 小时前
算法日常记录
java·算法·leetcode
27669582921 小时前
美团民宿 mtgsig 小程序 mtgsig1.2 分析
java·python·小程序·美团·mtgsig·mtgsig1.2·美团民宿
爱的叹息1 小时前
Java 连接 Redis 的驱动(Jedis、Lettuce、Redisson、Spring Data Redis)分类及对比
java·redis·spring
程序猿chen1 小时前
《JVM考古现场(十五):熵火燎原——从量子递归到热寂晶壁的代码涅槃》
java·jvm·git·后端·java-ee·区块链·量子计算
松韬2 小时前
Spring + Redisson:从 0 到 1 搭建高可用分布式缓存系统
java·redis·分布式·spring·缓存
绝顶少年2 小时前
Spring Boot 注解:深度解析与应用场景
java·spring boot·后端