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

静态代理

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

业务接口类 

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

//抽象业务
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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

raid5故障导致上层文件系统不可用的服务器数据恢复案例

服务器数据恢复环境: 一台服务器上有两组分别由4块SAS硬盘组建的raid5磁盘阵列,这两组raid5阵列划分LUN并组成LVM结构,格式化为EXT3文件系统。 服务器故障: 一组raid5阵列上的一块硬盘未知原因离线,热备盘上线替换离线…

Redis远程字典服务

目录 前言 1.NoSQL 1.1NOSQL和关系型数据库比较 1.2非关系型数据库的优势 1.3关系型数据库的优势 ​编辑 2.主流的NOSQL产品 键值(Key-Value)存储数据库 列存储数据库 文档型数据库 图形(Graph)数据库 3.Redis简介 redis的应用场景 4.命令操作 4.1字符串类型 s…

Linux内核的任务:

硬件与软件之间的中间层:内核在技术层面上充当硬件和软件之间的中间层,负责将应用程序的请求传递给硬件,并处理硬件设备和组件的寻址和操作。 应用程序的接口:对于应用程序来说,内核是它们与硬件之间的接口。应用程序通…

vscode 端口转发实现端口映射,实现端口自由

用vscode连接server进行开发, 是非常方便的,但很多时候,server的端口开放的很有限,那么就可以利用vscode进行端口映射 举一个应用场景: 先通过A利用vscode 连接B,然后再vscode 的port窗口进行端口转发&…

每日一刷——替换空格

题目描述: 请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。 我的思路:从左向右循环遍历字符串,定义一个空串。如果遇到空格&#xf…

【广州华锐互动】VR地铁消防逃生路线演练系统

随着城市轨道交通的不断发展,事故应急演练的重要性也越来越受到重视。而VR技术的应用,为地铁消防逃生路线演练带来了许多亮点,包括以下几个方面: 首先,VR技术可以提供高度真实的模拟场景。在传统的事故应急演练中&…

Lottie源代码解析

Lottie-iOS Lottie动画的原理: 一个完整动画View,是由很多个子Layer 组成,而每个子Layer主要通过shapes(形状),masks(蒙版),transform三大部分进行动画。Lottie框架通过…

【Linux】内存使用相关

free 命令 查看内存大小 free -g :G单位 free -h : 可读性较高较理解 free -m : MB单位 total: 总内存used: 正在运行的进程使用的内存(used total – free – buff/cache)free: 未使用的内存 (free total – used – buff/cache)shared: 多个进程共享的内存buffers: 内存保留…

linux安装mysql以及使用navicat连接mysql

目录 一、下载mysql 二、安装mysql 三、使用Navicat连接MySQL 四、常见问题 1、启动服务时报错 Failed to start mysql.service: Unit not found. 的解决方法。 2、登录过程出现:access denied for user’root’‘localhost’(using password:Yes) 的解决方…

常见的网络攻击

​ 1.僵木蠕毒 攻击业内习惯把僵尸网络、木马、蠕虫、感染型病毒合称为僵木蠕毒。从攻击路径来看,蠕虫和感染型病毒通过自身的能力进行主动传播,木马则需要渠道来进行投放,而由后门木马(部分具备蠕虫或感染传播能力)构…

一本通1919:【02NOIP普及组】选数

这道题感觉很好玩。 正文: 先放题目: 信息学奥赛一本通(C版)在线评测系统 (ssoier.cn)http://ybt.ssoier.cn:8088/problem_show.php?pid1919 描述 已知 n 个整数 x1,x2,…,xn,以及一个整数 k(k&#…

Flutter——最详细(NavigationRail)使用教程

NavigationRail 简介 一个 Material Design 小部件,旨在显示在应用程序的左侧或右侧,以便在少量视图(通常在三到五个视图之间)之间导航。 使用场景: 通过Row属性,左侧或右侧菜单栏按钮 属性作用onDestinati…

Excel之VLOOKUP()函数介绍

Excel之VLOOKUP()函数介绍 Excel的VLOOKUP函数语法: VLOOKUP(lookup_value, table_array, col_index_num, [range_lookup]) 参数说明: lookup_value:要查找的值或要比较的值。 table_array:包含要在其中进行查找的数据表的区…

[ 容器 ] Docker 基本管理

目录 一、Docker 概述1.1 Docker 是什么?1.2 Docker 的宗旨1.3 容器的优点1.4 Docker 与 虚拟机的区别1.5 容器在内核中支持的两种技术namespace的六大类型 二、Docker核心概念2.1 镜像2.2 容器2.3 仓库 三、安装 Docker四、docker 镜像操作五、 Docker 容器操作总结…

如何录音转文字:探寻声音的文字之舞

随着科技的飞速进步,人们对于信息的传递和记录变得越发便捷。在这个数字化时代,录音转文字技术无疑是一颗璀璨的明珠,它让声音和文字在交织中跳跃,为我们带来了新的感知和体验。在这篇文章中,我们将深入探讨录音转文字…

Python实现word简历中图片模糊

Python实现word简历中照片模糊——保护个人隐私的有效方法 一、引言背景 在现代招聘流程中,电子简历成为了主要的招聘方式之一。然而,简历中包含的个人信息往往涉及隐私问题,特别是照片。为了保护求职者的个人隐私和数据安全,许多…

Stable Diffusion生成图片参数查看与抹除

前几天分享了几张Stable Diffusion生成的艺术二维码,有同学反映不知道怎么查看图片的参数信息,还有的同学问怎么保护自己的图片生成参数不会泄露,这篇文章就来专门分享如何查看和抹除图片的参数。 查看图片的生成参数 1、打开Stable Diffus…

【密码学】一、概述

概述 1、密码学的发展历史1.1 古代密码时代1.2 机械密码时代1.3 信息密码时代1.4 现代密码时代 2、密码学的基本概念3、密码学的基本属性4、密码体制分类4.1 对称密码体制4.2 非对称加密体制 5、密码分析 1、密码学的发展历史 起因:保密通信和身份认证问题 根据时间…

Twisted Circuit

题目描述 输入格式 The input consists of four lines, each line containing a single digit 0 or 1. 输出格式 Output a single digit, 0 or 1. 题意翻译 读入四个整数 00 或者 11,作为如图所示的电路图的输入。请输出按照电路图运算后的结果。 感谢PC_DOS …

推荐一款在win、mac、android之间传递文件或消息的软件,LocalSend,前提需要在同一网络下

官方地址 https://github.com/localsend/localsend/releases/download/v1.10.0/LocalSend-1.10.0.dmg 可选择不同的设备进行发送接收,超级好用