结构型(一) - 代理模式

news2024/11/24 15:26:02

一、概念

代理模式(Proxy Pattern):它在不改变原始类(或叫被代理类)代码的情况下,通过引入代理类来给原始类附加新功能。

使用场景:代理模式最常用的一个应用场景就是,在业务系统中开发一些非功能性需求,比如:监控、统计、鉴权、限流、事务、幂等、日志。我们将这些附加功能与业务功能解耦,放到代理类中统一处理,让程序员只需要关注业务方面的开发。

二、实现

  • 静态代理

借鉴下面参考文章VPN的例子,实现了静态代理:
1、定义网站接口

public interface Website {
    void processRequest();
    void saveHistory();
}

2、实现网站Baidu实例

public class Baidu implements Website{
    @Override
    public void processRequest() {
        System.out.println("正在访问Baidu");
    }

    @Override
    public void saveHistory() {
        System.out.println("保存访问Baidu记录");
    }
}

3、访问baidu网站

public class Client {
    public static void main(String[] args) {
        Baidu baidu = new Baidu();
        baidu.processRequest();
        baidu.saveHistory();
    }
}

4、访问结果:
访问网站结果.png

5、实现网站Youtube实例

public class Youtube implements Website{
    @Override
    public void processRequest() {
        System.out.println("正在访问Youtube");
    }

    @Override
    public void saveHistory() {
        System.out.println("保存访问Youtube记录");
    }
}

6、如果我们要访问国外的网站Youtube,Facebook等,直接访问是不行的,我们就需要加一个vpn,登录vpn后可正常访问。所以我们需要在访问Youtube这些网站前加上vpn登录校验功能,如果未登录先登录vpn在去访问。但是如果每个网站的每个方法前挨个加判断太麻烦了,所以我们写一个代理类,统一给这些国外的网站加上登录校验功能。

public class VPN implements Website {
    private Website proxiedWebsite;
    public VPN (Website wb){
        this.proxiedWebsite = wb;
    }

    @Override
    public void processRequest() {
        loginVpn();
        proxiedWebsite.processRequest();
    }

    @Override
    public void saveHistory() {
        loginVpn();
        proxiedWebsite.saveHistory();
    }

    private void loginVpn() {
        System.out.println("校验vpn登录状态,已登录");
    }
}

总结:个人理解,vpn这里相当于一个网站代理,我们把要访问的网站给代理类,代理类会处理vpn登录等判断并帮我们访问我们需要的网站。vpn登录功能相对于之前的网站访问及网站历史记录等网站业务功能是相对独立的,所以直接加在原来代码中不合理,因此该功能抽出来用代理类去处理。

7、访问Youtube :

public class Client {
    public static void main(String[] args) {
        //Baidu baidu = new Baidu();
        //baidu.processRequest();
        
        //直接访问
        //Youtube youtube = new Youtube();
        //youtube.processRequest();
        //youtube.saveHistory();

        //代理访问
        Website youtube = new VPN(new Youtube());
        youtube.processRequest();
        youtube.saveHistory();
    }
}

8、运行结果:
访问结果1.png

总结:从上面的例子可以看出,VPN需要实现Website接口,代理类需要把实现类的方法都实现一遍。后面增加登录校验功能,就需要在每个实现方法中都加一遍。

  • 动态代理

动态代理就是我们不事先为每个原始类编写代理类,而是在运行的时候,动态地创建原始类对应的代理类,然后在系统中用代理类替换掉原始类。

代码实现:
1、动态代理实现,先实现接口InvocationHandler,然后通过Proxy类的newProxyInstance()方法创建这个代理。被代理类方法通过反射调用invoke执行,我们在每次执行前加一个vpn登录校验。

public class WebsiteHandler implements InvocationHandler {
    private Website proxiedObject;

    public WebsiteHandler(Website wb) {
        this.proxiedObject = wb;
    }

    public Website getProxyInstance() {
        return (Website) Proxy.newProxyInstance(this.getClass().getClassLoader()
                , proxiedObject.getClass().getInterfaces(), this);
    }

   @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        loginVpn();
        return method.invoke(proxiedObject, args);
    }

    private void loginVpn() {
        System.out.println("校验vpn登录状态,已登录");
    }
}

2、代理实现和调用

public class Client {
    public static void main(String[] args) {
        //Baidu baidu = new Baidu();
        //baidu.processRequest();
        
        Youtube youtube = new Youtube();
        WebsiteHandler websiteHandler = new WebsiteHandler(youtube);
        Website website = websiteHandler.getProxyInstance();
        website.processRequest();
        website.saveHistory();
    }
}

3、运行结果
访问结果2.png

总结:这里我们没有去写一个代理类,而是交给Proxy去生成,然后在InvocationHandlerinvoke方法去实际执行。这个代理类,是在运行阶段生成的,无需事前写好。从上面例子可以看到,如果加功能的话在反射调用的时候统一加上就行,无需像静态代理一样在每个实现方法中都加一遍。

参考文章:
设计模式之代理模式

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

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

相关文章

Lnton羚通算法算力云平台【PyTorch】教程:torch.nn.Softplus

torch.nn.Softplus 原型 CLASS torch.nn.Softplus(beta1, threshold20) 参数 beta (int) – Softplus里β \betaβ 值, 默认为 1. threshold (int) – 高于这个值恢复为线性函数,默认为 20. 图 代码 import torch import torch.nn as nnm nn.Softp…

电工-学习电工有哪些好处

学习电工有哪些好处?在哪学习电工? 学习电工有哪些好处?在哪学习电工?学习电工可以做什么?优势有哪些? 学习电工可以做什么?学习电工有哪些好处? 就业去向:可在企业单位…

Word怎么转换成PDF文档?多个Word转换成PDF步骤分享

word文档是一种非常好用的文件格式,可以帮助用户们很好的保存图片和文字内容,不过并不是只有word这一种文档类文件格式,还有一种pdf文档也深受用户们的欢迎,在工作或者学习过程中这两种文档是可以互相转换格式的,那么W…

如何安装指定版本node.js,安装旧版本node

1、查看当前是否安装node,如果安装了需要先卸载当前版本node 搜索控制面板 -> 找到程序/卸载程序 -> 在里面找到node -> 然后右击卸载 2、卸载完成后就要安装其他版本得node.js 找到想要安装的对应版本,安装.msi格式的安装包 注&#xff…

测试框架pytest教程(9)跳过测试skip和xfail

skip无条件跳过 使用装饰器 pytest.mark.skip(reason"no way of currently testing this") def test_example(faker):print("nihao")print(faker.words()) 方法内部调用 满足条件时跳过 def test_example():a1if a>0:pytest.skip("unsupported …

Unity 之 ScreenPointToRay() (将点转换成射线的方法)

文章目录 ScreenPointToRay() ScreenPointToRay() ScreenPointToRay() 是Unity中Camera类的一个方法,用于将屏幕上的一个点转换为一条射线。这条射线的起点是摄像机在屏幕上对应的点,方向是从摄像机出发指向那个点。这在进行射线命中检测时非常有用&…

如何远程管理服务器详解

文章目录 前言一、远程管理类型二、远程桌面三、telnet 命令行远程四、查看本地开放端口 前言 很多公司是有自己的机房的,机房里面会有若干个服务器为员工和用户提供服务。大家可以想想:假设这家公司有上百台服务器,我们作为网络工程师&…

探究Java spring中jdk代理和cglib代理!

面对新鲜事物,我们要先了解在去探索事物的本质-默 目录 一.介绍二者代理模式 1.1.Jdk代理模式 1.2cglib代理模式 1.3二者区别 1.3.1有无接口 1.3.2灵活性 1.4对于两种代理模式的总结 1.4.1jdk代理模式 1.4.2cglib代理模式 二.两种代理模式应用场景 2.1jd…

测试框架pytest教程(5)运行失败用例-rerun failed tests

# content of test_50.py import pytestpytest.mark.parametrize("i", range(50)) def test_num(i):if i in (17, 25):pytest.fail("bad luck") 运行这个文件,2个失败,48个通过。 要运行上次失败的测试用例,可以使用--l…

框架(Git基础详解及Git在idea中集成步骤)

目录 基础: idea集成Git并添加项目到git仓库 1.idea集成git,集成.git.exe文件 2.初始化本地Git仓库项目 3. 将工作区代码添加到暂存区 4.将暂存区代码添加到本地仓库 5.Git本地库操作 Idea集成Gitee并提交代码到第三方库 1.setting里搜索gitee 2.添…

什么是RNN(循环神经网络)

什么是RNN(循环神经网络) 循环神经网络(Recurrent Neural Network),在识别图像时,输入的每张图片都是孤立的,认出这张图片是苹果,并不会对认出下一张图片是梨造成影响。 但对语言来说,顺序是十分重要的,“…

Lua与C++交互(一)————堆栈

Lua与C交互(一)————堆栈 Lua虚拟机 什么是Lua虚拟机 Lua本身是用C语言实现的,它是跨平台语言,得益于它本身的Lua虚拟机。 虚拟机相对于物理机,借助于操作系统对物理机器(CPU等硬件)的一…

Java【手撕双指针】LeetCode 1089. “复写零“, 图文详解思路分析 + 代码

文章目录 前言一、复写零1, 题目2, 思路分析2.1, 从左往右 or 从右往左2.2, 找到最后一个保留的数 3, 代码展示 前言 各位读者好, 我是小陈, 这是我的个人主页, 希望我的专栏能够帮助到你: 📕 JavaSE基础: 基础语法, 类和对象, 封装继承多态, 接口, 综合小练习图书管…

SpringCloud Gateway服务网关的介绍与使用

目录 1、网关介绍2、SpringCloudGateway工作原理3、三大组件3.1 、Route(路由)3.2、断言 Predicate3.3、过滤器 filter 4、Gateway整合nacos的使用4.1 、引入依赖4.2、 编写基础类和启动类4.3、 编写基础配置和路由规则4.4 、测试结果 1、网关介绍 客户…

营销数字化|企业级 AIGC 工具的「iPhone 时刻」

2007 年,乔布斯发布了第一款 iPhone,从此彻底改变了手机行业的市场走向。iPhone 成功的背后,一个很重要的原因是:它让用户以更简单、更符合直觉的方式来使用手机。 如今,AIGC 工具也在等待它的「iPhone 时刻」&#xf…

C++信息学奥赛1119:矩阵交换行

解题思路&#xff1a;当输出时换行 解题程序&#xff1a; #include<iostream> using namespace std; int main() {int arr[5][5];// 输入矩阵元素for(int i0;i<5;i){for(int j0;j<5;j){cin>>arr[i][j];}} int n,m;cin>>n>>m;// 根据条件进行矩…

RT-Thread学习日记——点亮LED

最近开始接触RT-Thread&#xff0c;后面会单独建立专栏以此记录我的学习过程&#xff0c;如果能给你的学习提供参考&#xff0c;本人倍感荣幸。 学习工具&#xff1a;正点原子战舰开发板 一、、点亮LED 在RT-Thread的配置项里搜索LED可以看到和LED相关的很多内容&#xff0c…

AutoDev 1.1.3 登场,个性化 AI 辅助:私有化大模型、自主设计 prompt、定义独特规则...

在过去的半个月里&#xff0c;我们为开源辅助编程工具 AutoDev 添加了更强大的自定义能力&#xff0c;现在你可以&#xff1a; 使用自己部署的开源大模型自己配置 Intellij IDEA 中的行为自定义开发过程中的规范 当然了&#xff0c;如果您自身拥有开发能力的话&#xff0c;建议…

无涯教程-PHP - XML

简单的XML解析器解析 Name&#xff0c; attributes 和 textual content&#xff0c;简单的XML函数如下所示- simplexml_load_file() 此函数接受文件路径作为第一个参数&#xff0c;这是必需的。 simplexml_load_file(($fileName,$class,$options,$ns,$is_prefix) simplexml…

springMVC Unix 文件参数变更漏洞修复

错误信息如下&#xff1a; 解决方案&#xff1a; 原因&#xff1a;未对用户输入正确执行危险字符清理 未检查用户输入中是否包含“…”&#xff08;两个点&#xff09;字符串&#xff0c;比如 url 为 /login?action…/webapps/RTJEKSWTN26635&typerandomCode cookie为Coo…