【设计模式】之代理模式(两种)

系列文章目录

(其他设计模式可以参考 👉👉👉)设计模式_小杰不秃头的博客 😊😄😛


前言

今天继续给大家介绍23种设计模式中的代理模式,熟悉Spring的小伙伴都知道,Aop使用的就是代理模式,所以,代理模式还是非常重要的,在工作中用的也是非常的多。🌈


一、代理模式

代理模式(Proxy Pattern)面向对象编程 中的一种设计模式,它为其他对象提供一个代理占位符 ,以控制对这个对象的访问。代理对象在客户端目标对象 之间起到中介 的作用,客户端并不直接与目标对象交互,而是通过代理对象 来间接调用目标对象的方法。(简单理解就是"房子中介"的一个角色)

特点

  1. 中介作用:代理对象作为客户端和目标对象之间的中介,可以拦截或修改客户端对目标对象的请求。
  2. 功能增强:可以在不修改目标对象代码的前提下,通过代理对象为目标对象增加额外的功能。如:Spring中的AOP
  3. 控制访问:代理对象可以控制对目标对象的访问,比如检查权限、记录日志、实现延迟加载等。

举一个简单的例子帮助大家理解,假如说你想买一个房子,但是你没有时间去挑选,所以你就找了一个房子中介帮你去找房子,这个过程就是一个代理的过程,房子中介就是一个代理对象。

二、静态代理

1、静态代理定义和特点

静态代理(Static Proxy):是在程序编译时确定代理类的代码,代理类和目标类实现了相同的接口。静态代理的实现相对简单,代理对象和目标对象实现相同的接口,客户端通过代理对象调用目标对象的方法。

特点:静态代理需要手动编写代理类的代码,因此当接口发生变化时,代理类也需要相应地修改。由于代理类在编译期间就已经确定,因此性能相对较高。但是,静态代理只能为给定接口的实现类做代理,如果接口不同则需要重新定义不同的代理类。

2、使用场景

使用场景:静态代理通常用于为一些功能较为简单的类提供代理,如增加日志记录、性能监控等功能。由于静态代理需要手动编写代理类的代码,因此它通常适用于接口稳定、功能较为简单的场景。

3、静态代理的简单实现

这里举一个比较粗糙的例子,模拟插入订单的这个业务场景。

跟我们平时开发的一样,首先创建实体类Order

java 复制代码
public class Order {
    private String info;
    private String userId;

    public String getInfo() {
        return info;
    }

    public void setInfo(String info) {
        this.info = info;
    }

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    @Override
    public String toString() {
        return "Order{" +
                "info='" + info + '\'' +
                ", userId='" + userId + '\'' +
                '}';
    }
}

创建持久层的接口和实现类

java 复制代码
public interface OrderDao {
    int insertOrder(Order order);
}

public class OrderDaoImpl implements OrderDao {
    @Override
    public int insertOrder(Order order) {
        System.out.println("持久层...插入订单..."+order.toString());
        return 1;
    }
}

创建服务层的接口和实现类

java 复制代码
public interface OrderService {
    int insertOrder(Order order);
}

public class OrderServiceImpl implements OrderService {
    private OrderDao orderDao;
    @Override
    public int insertOrder(Order order) {
        orderDao = new OrderDaoImpl();
        System.out.println("业务层...调用持久层insertOrder方法...");
        return orderDao.insertOrder(order);
    }
}

关键一步,创建静态代理对象

java 复制代码
public class OrderServiceImplStaticProxy {
    private OrderService orderService;

    public int insertOrder(Order order){
        before();
        orderService = new OrderServiceImpl();
        int result = orderService.insertOrder(order);
        after();
        return result;
    }

    private void after() {
        System.out.println("静态代理对象...提交事务...");
    }

    private void before() {
        System.out.println("静态代理对象...开启事务...");
    }
}

测试

java 复制代码
public class Test {
    public static void main(String[] args) {
        Order order = new Order();
        order.setInfo("xxxx笔记本电脑");
        order.setUserId("1");
        OrderServiceImplStaticProxy proxy = new OrderServiceImplStaticProxy();
        proxy.insertOrder(order);
    }
}

/*打印结果:
静态代理对象...开启事务...
业务层...调用持久层insertOrder方法...
持久层...插入订单...Order{info='xxxx笔记本电脑', userId='1'}
静态代理对象...提交事务...
*/

三、动态代理

1、动态代理定义和特点

**动态代理(Dynamic Proxy)**是在程序运行过程中通过反射机制动态生成代理类的代码,实现对目标类的代理访问。动态代理可以代理任意实现了接口的类,不受接口的限制。

特点:动态代理可以根据具体需求动态生成代理类,避免了手动编写代理类的繁琐工作,方便接口的扩展和修改。由于动态代理在程序运行时生成代理类的代码,因此性能较静态代理略低。但是,动态代理的灵活性 更高,可以代理任意实现了接口的类。

2、使用场景

使用场景:动态代理广泛应用于各种场景,包括但不限于AOP(面向切面编程)、远程方法调用、RPC(远程 过程调用)等。通过动态代理,我们可以实现对目标方法的拦截和增强,将系统的横切关注点(如日志记录、性能统计等)与业务逻辑代码进行解耦,提高代码的可维护性和可扩展性。

3、动态代理的简单实现

这里例子还以插入订单为例,其他都不变,只需将静态代理换为动态代理就可。

java 复制代码
public class OrderServiceImplDynamicProxy implements InvocationHandler {
    private Object orderService;
    public OrderServiceImplDynamicProxy(Object service){
        this.orderService = service;
    }
    public Object bind(){
        //创建动态代理对象
        return Proxy.newProxyInstance(orderService.getClass().getClassLoader(), orderService.getClass().getInterfaces(),this);
    }
    private void after() {
        System.out.println("动态代理对象...提交事务...");
    }

    private void before() {
        System.out.println("动态代理对象...开启事务...");
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        Object o = method.invoke(orderService, args);
        after();
        return o;
    }
}

测试

java 复制代码
public class Test {
    public static void main(String[] args) {
        OrderService service = (OrderService)new OrderServiceImplDynamicProxy(new OrderServiceImpl()).bind();

        Order order = new Order();
        order.setInfo("xxx手机");
        order.setUserId("2");

        service.insertOrder(order);
    }
}

/*打印结果:
动态代理对象...开启事务...
业务层...调用持久层insertOrder方法...
持久层...插入订单...Order{info='xxx手机', userId='2'}
动态代理对象...提交事务...
*/

总结

总结来说,静态代理和动态代理各有优缺点,适用于不同的场景。静态代理适用于接口稳定、功能较为简单的场景,而动态代理则适用于需要灵活代理任意实现了接口的类的场景。

相关推荐
Ling_suu18 分钟前
Spring——单元测试
java·spring·单元测试
ModelBulider20 分钟前
十三、注解配置SpringMVC
java·开发语言·数据库·sql·mysql
苹果酱056734 分钟前
C语言 char 字符串 - C语言零基础入门教程
java·开发语言·spring boot·mysql·中间件
csucoderlee41 分钟前
eclipse mat leak suspects report和 component report的区别
java·ide·eclipse
代码小鑫1 小时前
A032-基于Spring Boot的健康医院门诊在线挂号系统
java·开发语言·spring boot·后端·spring·毕业设计
训山1 小时前
4000字浅谈Java网络编程
java·开发语言·网络
VertexGeek1 小时前
Rust学习(四):作用域、所有权和生命周期:
java·学习·rust
喔喔咿哈哈1 小时前
【手撕 Spring】 -- Bean 的创建以及获取
java·后端·spring·面试·开源·github
码农小丘1 小时前
了解springboot国际化用途以及使用
java·spring boot·spring
卡皮巴拉吖1 小时前
【JavaEE初阶】多线程上部
java·jvm·java-ee