代理模式【静态代理和动态代理实现业务功能扩展】

news2024/11/25 14:46:22

静态代理

  • 我们在不修改业务的情况下想要给它增加一些功能,这就需要使用代理模式。
  • 我们不会在原有业务上直接修改,为了避免修改导致程序不可逆转的破坏。
  • 三种角色:抽象角色-接口、真实角色-实现类和代理角色-代理类。
  • 真实角色和代理角色继承的是同一个抽象角色接口!

业务接口类 

负责抽象出业务需要的功能。

//抽象业务
public interface UserService {
    public void add();
    public void delete();
    public void update();
    public void query();
}

业务的实现类

public class UserServiceImpl implements UserService{
    @Override
    public void add() {
        System.out.println("增加了一个用户");
    }

    @Override
    public void delete() {
        System.out.println("删除了一个用户");
    }

    @Override
    public void update() {
        System.out.println("修改了一个用户");
    }

    @Override
    public void query() {
        System.out.println("查询了一个用户");
    }
}

代理类

假如我们现在要给业务增加一个新的功能-输出日志功能,我们需要通过一个代理类来实现 ,而不是直接在旧业务上修改代码。

我们增加一个 log 方法(拓展功能),我们需要一个 set 方法来使代理能够通过旧的实现类调用旧的业务。


//代理实现增删改查
public class UserServiceProxy implements UserService{

    UserServiceImpl userService;

    public void setUserService(UserServiceImpl userService) {
        this.userService = userService;
    }

    @Override
    public void add() {
        log("add");
        userService.add();
    }

    @Override
    public void delete() {
        log("delete");
        userService.delete();
    }

    @Override
    public void update() {
        log("update");
        userService.update();
    }

    @Override
    public void query() {
        log("query");
        userService.query();
    }

    public void log(String message){
        System.out.println("使用了" + message + "方法");
    }
}

测试

这样我们的只需要给代理设置旧业务的实现类就实现了业务的功能扩展。

public class Client {
    public static void main(String[] args) {
        UserServiceImpl service = new UserServiceImpl();
        UserServiceProxy proxy = new UserServiceProxy();
        proxy.setUserService(service);
        proxy.add();
    }
}

动态代理

  • 动态代理个静态代理角色一样(抽象角色-接口、真实角色-实现类和代理角色-代理类)
  • 动态代理的代理类是通过反射动态生成的!
  • 动态代理按照实现可以分我:基于接口的 和 基于类的动态代理。
    • 基于接口:JDK 动态代理
    • 基于类:cglib
  • 需要了解两个类:Proxy:代理、InvocationHandler:调用处理程序。
  • 一个动态代理类就是一个接口!
  • 一个动态代理类可以代理多个真实角色类,只需要继承同一个业务接口即可。
  • 使用动态代理可以大大减少代码量!因为它使用了反射!

Proxy:

Proxy 一共只有4个方法:

 

 

 InvocationHandler:

InvocationHandler是一个接口!

InvocationHandler 整个类里只有一个方法:invoke方法。 

 动态代理的实现

抽象角色

//抽象业务
public interface UserService {
    public void add();
    public void delete();
    public void update();
    public void query();
}

真实角色

public class UserServiceImpl implements UserService {
    @Override
    public void add() {
        System.out.println("增加了一个用户");
    }

    @Override
    public void delete() {
        System.out.println("删除了一个用户");
    }

    @Override
    public void update() {
        System.out.println("修改了一个用户");
    }

    @Override
    public void query() {
        System.out.println("查询了一个用户");
    }
}

代理角色

使用 Object 作为抽象角色,这样这一个代理类就可以当做工具类来给任何真实角色进行功能扩展!

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

//代理处理程序
public class ProxyInvocationHandler implements InvocationHandler {

    //被代理的接口
    private Object target;

    public void setUserService(Object target) {
        this.target = target;
    }

    //生成并得到代理类
    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(),this);
    }

    //处理代理实例,调用抽象接口的方法,并返回结果
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        //动态代理的本质就是使用反射机制实现!
        fun1();
        log(method.getName());
        Object result = method.invoke(target, args);
        fun2();
        return result;
    }

    public void fun1(){
        System.out.println("扩展功能1");
    }
    public void fun2(){
        System.out.println("扩展功能2");
    }
    public void log(String message){
        System.out.println("执行了" + message + "方法");
    }
}

测试

public class Client {
    public static void main(String[] args) {
        //真实角色
        UserServiceImpl userService = new UserServiceImpl();
        //代理角色
        ProxyInvocationHandler handler = new ProxyInvocationHandler();
        //设置要代理的真实对象
        handler.setUserService(userService);

        //动态生成代理类
        UserService proxy = (UserService) handler.getProxy();
        proxy.add();
        proxy.delete();

    }
}

输出结果:

扩展功能1
执行了add方法
增加了一个用户
扩展功能2
扩展功能1
执行了delete方法
删除了一个用户
扩展功能2

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/765842.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ARM 架构是什么?

ARM(Advanced RISC Machines)架构是一种处理器架构,它是一种精简指令集计算机(RISC)架构。ARM架构最初由ARM Holdings(现在是SoftBank Group的子公司)开发,并在1980年代末和1990年代…

K8s核心概念 Controller

K8s核心概念 Controller Kubernetes核心概念 Controller一、pod控制器controller1.1 Controller作用及分类1.2 Deployment1.2.1 Replicaset控制器的功能1.2.2 Deployment控制器的功能1.2.3 Deployment用于部署无状态应用1.2.4 创建deployment类型应用1.2.5 访问deployment1.2.6…

SpringCloud集成Sleuth+Zipkin进行链路追踪

关于微服务链路追踪的一些概念:【分布式链路追踪】 文章目录 1、整合Seluth2、日志信息分析3、Zipkin介绍4、Zipkin服务端安装5、搭配Sleuth整合客户端Zipkin6、收集数据7、存储trace数据 1、整合Seluth Spring Cloud Sleuth是一个用于追踪的工具,它可以…

ThinkPHP 多对多关联

用多对多关联的前提 如果模型 A 多对多关联模型 C,必须存在一张中间表 B 记录着双方的主键,因为就是靠着这张中间表 B 记录着模型 A 与模型 C 的关系。 举例,数据表结构如下 // 商品表 goodsgoods_id - integer // 商品主键goods_name - va…

【C#】并行编程实战:使用延迟初始化提高性能

在前面的章节中讨论了 C# 中线程安全并发集合,有助于提高代码性能、降低同步开销。本章将讨论更多有助于提高性能的概念,包括使用自定义实现的内置构造。 毕竟,对于多线程编程来讲,最核心的需求就是为了性能。 延迟初始化 - .NET…

手机怎么编辑pdf?这几款工具可以实现

手机怎么编辑pdf?在如今的数字时代,PDF文档已经成为了一种标准的文件格式。然而,当我们需要编辑这些PDF文档时,我们往往需要使用电脑上的专业软件,这给我们带来了很大的不便。不过,有许多手机应用程序可以让…

AIGC 大模型纷纷部署,企业如何为 AI 数据降本增效

编辑 | 宋慧 出品 | CSDN 云计算 AIGC 从年初开始持续爆火,国内各种大模型纷纷涌现,其中模型参数轻松突破千亿数量级。模型中数据的形态、部署也是多种多样的,庞大数据量背后的管理和成本不容小觑。 混合数据厂商肯睿 Cloudera 今年相继发布…

设计模式的概述

目录 分类 创建型模式 结构型模式 行为型模式 类之间的关系 关联关系 聚合关系 组合关系 依赖关系 继承关系 实现关系 设计原则 开闭原则 里氏代换原则 依赖倒转原则 接口隔离原则 合成复用原则 一、分类 创建型模式 用于描述“怎样创建对象”,它…

线程池的学习(一)

转载:Java 线程池 线程池的创建方式 方式一:创建单一线程的线程池 newSingleThreadExecutor 特点: 线程池中只包含 1 个线程,存活时间是无限的按照提交顺序执行任务唯一线程繁忙时,新提交的任务会被加入到阻塞队列…

Java springBoot项目报LDAP health check failed

报错内容如下: 在bootstrap.yml文件里加 management:health:ldap:enabled: false 配置。 或者在application.properties文件里加: management.health.ldap.enabledfalse 参考答案:LDAP health check failed 难道没有人遇到这样的问题吗&…

我造了一个新的词汇:信息湍流

信息湍流 信息湍流的简介起因有出现信息湍流的领域如何做信息湍流的计算 信息湍流的简介 在物流学中,一个物体从一个位置到另外一个位置,我们可以通过精确的公式计算来预测出新位置。 而水和气体则是大量一个一个物体组成的新物体,称为&…

Docker安装以及基础镜像的使用

Docker 安装 Docker 要求 CentOS 系统的内核版本高于 3.10 uname -r使用 root 权限登录 su # 输入密码更新 yum yum -y update卸载旧版本的 docker yum remove ‐y docker*安装需要的软件包 yum -y install yum-utils设置 yum 源,并更新 yum 包的索引 yum-config-ma…

凝心聚力,同为科技(TOWE)2023年中会议暨团建活动圆满举行

01凝心聚力 奋勇冲刺——年中会议现场 年中会议现场 时光冉冉,2023年已过半,7月4日-11日,为回望过往、总结成果、复盘经验,确保顺利完成公司年度目标,增强团队凝聚力、激发员工活力,深化企业文化建设&…

15 - 堆栈 - 大顶堆

前面我们学习了小顶堆,相信大家都已经有点概念了,今天来了解一下大顶堆。 大顶堆示意图 堆数组存放的公式 我们用简单的公式来描述一下堆的定义就是: 大顶堆:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2] 小顶堆:arr[i] <= arr[2i+1] && a…

两股热潮如何汇聚:当数字孪生遇上元宇宙

引言 随着科技的迅猛发展&#xff0c;数字孪生和元宇宙已成为当今技术界备受关注的两股热潮。这两个概念各自都在不同领域取得了突破性进展&#xff0c;但在最近的发展中&#xff0c;人们开始发现它们之间存在着潜在的契合点。本文将探讨数字孪生和元宇宙的定义、特点&#xf…

【【51单片机蜂鸣器实现起风了】】

哀伤如同风&#xff0c;消失无影踪。 前面的有两个非常关键的点希望兄弟们明白 我一开始也失算了 这里兄弟们注意务必改成int 不然会超出 就会出现播放一半从头开始的情况 下面是两份起风了代码直接附上main.c 因为另外的其实和我之前说的模板都一样复制粘贴就行 为什么是…

M1 Mac如何安装CentOS7虚拟机(图文详细解说)

1、下载相应的文件 2、打开VMware Fusion pro进行安装 3、 输入许可证密钥 4、 将CentOS-7拖入“从光盘或映像中安装”中 5、点击继续 6、选择其他-->其他64位ARM-->继续 7、进行自定设置 8、这里更改名为“Centos7”&#xff08;不要加空格&#xff09;&#xff0c;存…

2023 Testing Expo倒计时-聚焦Softing 9003展位

请点击此处&#xff0c;即可进行在线登记报名并了解更多信息&#xff01;

ES系列--文档处理

一、文档冲突 当我们使用 index API 更新文档 &#xff0c;可以一次性读取原始文档&#xff0c;做我们的修改&#xff0c;然后重 新索引 整个文档 。 最近的索引请求将获胜&#xff1a;无论最后哪一个文档被索引&#xff0c;都将被唯一存 储在 Elasticsearch 中。如果其他人同时…

Java-生成数据库设计文档

目录 场景screw 官网介绍接口编写 场景 在企业开发中&#xff0c;有些公司会要求开发人员编写数据库表结构文档&#xff0c;这项工作没啥技术含量而且很繁琐&#xff0c;每当有表发生更改时就需要维护这个文档&#xff0c;或者是需要交付数据库设计文档和导出数据库设计文档这类…