深入浅出设计模式 - 代理模式

news2024/9/20 22:35:31

博主介绍: ✌博主从事应用安全和大数据领域,有8年研发经验,5年面试官经验,Java技术专家✌

Java知识图谱点击链接:体系化学习Java(Java面试专题)

💕💕 感兴趣的同学可以收藏关注下不然下次找不到哟💕💕

在这里插入图片描述

文章目录

  • 1、什么是代理模式
  • 2、代理模式有什么优缺点
  • 3、代理模式的应用场景
  • 4、代理模式的结构
  • 5、3种代理模式
  • 6、静态代理模式的代码案例
  • 7、JDK 动态代理模式的代码案例
  • 8、 Cglib 代理模式的代码案例

1、什么是代理模式

代理模式是一种结构型设计模式,它为其他对象提供一种代理以控制对这个对象的访问。代理对象充当了客户端和目标对象之间的中介,客户端通过代理对象访问目标对象,从而实现了对目标对象的控制。代理模式主要解决了直接访问某些对象时可能存在的问题,例如对象的创建和销毁成本过高、对象的访问需要额外的控制等。代理模式分为静态代理和动态代理两种方式,其中静态代理需要在编译期间就确定代理对象,而动态代理则在运行时动态生成代理对象。代理模式在实际应用中广泛使用,例如远程代理、虚拟代理、安全代理、缓存代理等。

2、代理模式有什么优缺点

代理模式的优点:

  1. 代理模式能够实现客户端和目标对象之间的解耦,客户端不需要知道目标对象的具体实现细节,只需要通过代理对象来访问目标对象即可。

  2. 代理模式可以提高系统的安全性,代理对象可以在访问目标对象之前进行权限检查等操作,从而保证系统的安全性。

  3. 代理模式可以提高系统的性能,例如使用缓存代理可以避免频繁访问目标对象,从而提高系统的性能。

  4. 代理模式可以实现懒加载,即在需要访问目标对象时才创建目标对象,从而避免了不必要的资源浪费。

代理模式的缺点:

  1. 代理模式会增加系统的复杂度,引入了额外的代理类,增加了系统的结构复杂度。

  2. 代理模式可能会降低系统的性能,特别是在使用远程代理时,由于网络通信的开销,可能会导致系统的性能下降。

  3. 代理模式可能会导致代码的维护难度增加,特别是在使用动态代理时,由于代码的生成是在运行时进行的,可能会导致程序的调试和维护难度增加。

3、代理模式的应用场景

代理模式的应用场景有很多,以下是一些常见的应用场景:

  1. 远程代理:当客户端需要访问远程对象时,可以使用远程代理来实现,远程代理负责与远程对象进行通信,并将结果返回给客户端。

  2. 虚拟代理:当创建一个对象的代价很大时,可以使用虚拟代理来延迟对象的创建,只有在真正需要使用对象时才创建对象。

  3. 安全代理:当需要控制对对象的访问时,可以使用安全代理来限制对对象的访问,例如只允许特定的用户访问对象。

  4. 缓存代理:当需要缓存对象的结果时,可以使用缓存代理来缓存对象的结果,从而避免重复计算。

  5. 日志代理:当需要记录对象的访问日志时,可以使用日志代理来记录对象的访问日志,例如记录对象的访问时间、访问次数等信息。

  6. 延迟加载代理:当需要延迟加载对象时,可以使用延迟加载代理来实现,延迟加载代理负责在需要访问对象时加载对象,并将结果返回给客户端。

  7. 权限代理:当需要对对象进行权限控制时,可以使用权限代理来限制对对象的访问,例如只允许特定的用户或角色访问对象。

代理模式适用于需要在访问对象时增加一些额外的处理逻辑的场景,例如控制访问、缓存结果、记录日志、延迟加载等。

4、代理模式的结构

代理模式的结构包含以下几个角色:

  1. 抽象主题(Subject):定义了真实主题和代理主题的公共接口,客户端通过该接口访问真实主题和代理主题。

  2. 真实主题(Real Subject):定义了代理所代表的真实对象,是代理模式中被代理的对象,客户端最终访问的就是真实主题。

  3. 代理主题(Proxy):保存一个引用使得代理可以访问真实主题,并提供一个与真实主题相同的接口,这样代理就可以用来代替真实主题。

代理模式的结构图如下所示:

|  Subject  |<---------|   Client   |
            +----------+          +------------+
                 /|\                          |
                  |                           |
                  |                           |
            +------------+          +------------+
            | RealSubject|          |    Proxy   |
            +------------+          +------------+

在这个结构中,客户端通过访问抽象主题接口来访问真实主题和代理主题,代理主题保存了一个对真实主题的引用,可以通过该引用来访问真实主题。客户端可以通过代理主题来访问真实主题,代理主题可以在访问真实主题前后进行一些额外的处理,例如控制访问、缓存结果、记录日志、延迟加载等。

5、3种代理模式

代理模式有以下三种常见的实现方式:

  1. 静态代理模式

静态代理模式是指由程序员创建代理类或特定工具自动生成源代码来实现代理的方式。在静态代理模式中,代理类和真实主题类都实现了相同的接口或继承了相同的父类,客户端通过代理类来访问真实主题类,代理类在调用真实主题类的方法前后可以进行一些额外的处理。静态代理模式的缺点是代理类和真实主题类需要实现相同的接口或继承相同的父类,这样会增加代码的复杂度。

  1. JDK 动态代理模式

动态代理模式是指在程序运行时根据需要动态创建代理类的方式。在动态代理模式中,代理类不需要实现与真实主题类相同的接口或继承相同的父类,代理类通过反射机制来调用真实主题类的方法,并在调用前后进行一些额外的处理。动态代理模式的优点是可以在程序运行时动态创建代理类,不需要编写额外的代码,但是需要了解反射机制。

  1. Cglib 代理模式

Cglib 代理模式是指使用 Cglib 库来动态生成代理类的方式。在 Cglib 代理模式中,代理类是真实主题类的子类,代理类通过重写真实主题类的方法来调用真实主题类的方法,并在调用前后进行一些额外的处理。Cglib 代理模式的优点是不需要实现相同的接口或继承相同的父类,可以对任意类进行代理,但是需要引入 Cglib 库。

6、静态代理模式的代码案例

静态代理模式是一种代理模式的实现方式,它通过创建一个代理类来包装真实的对象,从而实现对真实对象的控制和管理。以下是一个简单的静态代理模式的代码案例:

首先,定义一个公共接口 Subject ,它包含了真实对象和代理对象都需要实现的方法:

package com.pany.camp.design.principle.proxy.statics;

/**
 *
 * @description:  公共接口
 * @copyright: @Copyright (c) 2022 
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0 
 * @createTime: 2023-06-27 12:47
 */
public interface Subject {
    void request();
}

然后,定义一个真实对象类 RealSubject ,它实现了 Subject 接口中的 request() 方法:

package com.pany.camp.design.principle.proxy.statics;

/**
 *
 * @description:  真实对象类
 * @copyright: @Copyright (c) 2022 
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0 
 * @createTime: 2023-06-27 12:47
 */
public class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("RealSubject: handling request.");
    }
}

接下来,定义一个代理类 ProxySubject ,它也实现了 Subject 接口,并包含一个真实对象的引用:

package com.pany.camp.design.principle.proxy.statics;

/**
 *
 * @description:  代理类
 * @copyright: @Copyright (c) 2022 
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0 
 * @createTime: 2023-06-27 12:48
 */
public class ProxySubject implements Subject {
    
    private RealSubject realSubject;

    public ProxySubject(RealSubject realSubject) {
        this.realSubject = realSubject;
    }

    @Override
    public void request() {
        System.out.println("ProxySubject: handling request.");
        realSubject.request();
    }
}

在 ProxySubject 类中,实现了 request() 方法,并在其中调用了真实对象的 request() 方法。通过这种方式,代理对象可以在调用真实对象的方法前后,执行一些额外的操作,从而实现对真实对象的控制和管理。

最后,可以编写一个测试类来测试静态代理模式的实现:

package com.pany.camp.design.principle.proxy.statics;

/**
 *
 * @description:  客户端
 * @copyright: @Copyright (c) 2022 
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0 
 * @createTime: 2023-06-27 12:48
 */
public class Client {

    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        ProxySubject proxySubject = new ProxySubject(realSubject);
        proxySubject.request();
    }
}

输出结果如下:

Connected to the target VM, address: '127.0.0.1:57082', transport: 'socket'
ProxySubject: handling request.
RealSubject: handling request.
Disconnected from the target VM, address: '127.0.0.1:57082', transport: 'socket'

Process finished with exit code 0

在测试类中,首先创建一个真实对象 RealSubject ,然后创建一个代理对象 ProxySubject ,并将真实对象作为参数传递给代理对象。最后,调用代理对象的 request() 方法,即可执行代理对象和真实对象的方法。

通过上述代码案例,可以看出静态代理模式的实现方式。静态代理模式的优点是实现简单,易于理解和维护,同时可以在代理对象中添加额外的操作。缺点是需要手动编写代理类,如果要代理多个真实对象,代码量会增加,并且不利于代码的复用。

7、JDK 动态代理模式的代码案例

JDK 动态代理模式是一种代理模式的实现方式,它通过在运行时动态生成代理类来包装真实的对象,从而实现对真实对象的控制和管理。以下是一个简单的 JDK 动态代理模式的代码案例:

首先,定义一个公共接口 Subject ,它包含了真实对象和代理对象都需要实现的方法:

package com.pany.camp.design.principle.proxy.jdk;

/**
 *
 * @description:  公共接口
 * @copyright: @Copyright (c) 2022 
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0 
 * @createTime: 2023-06-27 12:50
 */
public interface Subject {
    void request();
}

然后,定义一个真实对象类 RealSubject ,它实现了 Subject 接口中的 request() 方法:

package com.pany.camp.design.principle.proxy.jdk;

/**
 *
 * @description:  真实对象类
 * @copyright: @Copyright (c) 2022 
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0 
 * @createTime: 2023-06-27 12:51
 */
public class RealSubject implements Subject {
    
    @Override
    public void request() {
        System.out.println("RealSubject: handling request.");
    }
}

接下来,定义一个代理类 ProxySubject ,它也实现了 Subject 接口,并包含一个真实对象类引用:

package com.pany.camp.design.principle.proxy.jdk;

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

/**
 * @description: 代理类
 * @copyright: @Copyright (c) 2022
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0
 * @createTime: 2023-06-27 12:52
 */
public class ProxySubject implements InvocationHandler {
    private Object realSubject;

    public ProxySubject(Object realSubject) {
        this.realSubject = realSubject;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("ProxySubject: handling request.");
        Object result = method.invoke(realSubject, args);
        return result;
    }
}

在 ProxySubject 类中,实现了 InvocationHandler 接口,并重写了其中的 invoke() 方法。在 invoke() 方法中,先执行代理对象的一些额外操作,然后再调用真实对象的方法,并将返回值返回给调用者。

最后,可以编写一个测试类来测试 JDK 动态代理模式的实现:

package com.pany.camp.design.principle.proxy.jdk;

import java.lang.reflect.Proxy;

/**
 *
 * @description:  客户端
 * @copyright: @Copyright (c) 2022 
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0 
 * @createTime: 2023-06-27 12:52
 */
public class Client {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        ProxySubject proxySubject = new ProxySubject(realSubject);
        Subject proxyInstance = (Subject) Proxy.newProxyInstance(
            realSubject.getClass().getClassLoader(),
            realSubject.getClass().getInterfaces(),
            proxySubject
        );
        proxyInstance.request();
    }
}


输出结果如下:

Connected to the target VM, address: '127.0.0.1:64018', transport: 'socket'
ProxySubject: handling request.
RealSubject: handling request.
Disconnected from the target VM, address: '127.0.0.1:64018', transport: 'socket'

Process finished with exit code 0

在测试类中,首先创建一个真实对象 RealSubject ,然后创建一个代理对象 ProxySubject ,并将真实对象作为参数传递给代理对象。最后,通过 Proxy.newProxyInstance() 方法动态生成代理类,并将代理对象转换成 Subject 接口类型,即可执行代理对象和真实对象的方法。

通过上述代码案例,可以看出 JDK 动态代理模式的实现方式。JDK 动态代理模式的优点是不需要手动编写代理类,可以在运行时动态生成代理类,同时可以代理多个真实对象,代码量相对较少,并且便于代码的复用。缺点是只能代理接口,无法代理类,且需要真实对象实现接口。

8、 Cglib 代理模式的代码案例

Cglib 代理模式是一种代理模式的实现方式,它通过继承的方式来生成代理类,从而实现对真实对象的控制和管理。以下是一个简单的 Cglib 代理模式的代码案例:
首先,引入 Cglib 相关依赖:

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.3.0</version>
</dependency>

然后,定义一个公共接口 Subject ,它包含了真实对象和代理对象都需要实现的方法:

package com.pany.camp.design.principle.proxy.cglib;

/**
 *
 * @description:  公共接口
 * @copyright: @Copyright (c) 2022 
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0 
 * @createTime: 2023-06-27 12:55 
 */
public interface Subject {
    void request();
}

接下来,定义一个真实对象类 RealSubject ,它实现了 Subject 接口中的 request() 方法:

package com.pany.camp.design.principle.proxy.cglib;

/**
 *
 * @description:  真实对象类
 * @copyright: @Copyright (c) 2022
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0
 * @createTime: 2023-06-27 12:56
 */
public class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("RealSubject: handling request.");
    }
}

然后,定义一个代理类 ProxySubject ,它继承了 Cglib 的 MethodInterceptor 类,并包含一个真实对象引用:

package com.pany.camp.design.principle.proxy.cglib;

import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 *
 * @description:  代理类
 * @copyright: @Copyright (c) 2022 
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0 
 * @createTime: 2023-06-27 12:57
 */
public class ProxySubject implements MethodInterceptor {

    private Object realSubject;

    public ProxySubject(Object realSubject) {
        this.realSubject = realSubject;
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("ProxySubject: handling request.");
        Object result = method.invoke(realSubject, objects);
        return result;
    }
}

在 ProxySubject 类中,实现了 MethodInterceptor 接口,并重写了其中的 intercept() 方法。在 intercept() 方法中,先执行代理对象的一些额外操作,然后再调用真实对象的方法,并将返回值返回给调用者。
最后,可以编写一个测试类来测试 Cglib 代理模式的实现:

package com.pany.camp.design.principle.proxy.cglib;

import org.springframework.cglib.proxy.Enhancer;

/**
 *
 * @description: 客户端
 * @copyright: @Copyright (c) 2022
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0
 * @createTime: 2023-06-27 12:58
 */
public class Client {

    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(RealSubject.class);
        enhancer.setCallback(new ProxySubject(new RealSubject()));
        RealSubject proxyInstance = (RealSubject) enhancer.create();
        proxyInstance.request();
    }
}

输出结果如下:

ProxySubject: handling request.
RealSubject: handling request.

Process finished with exit code 0

在测试类中,首先创建一个 Enhancer 对象,然后设置其父类为真实对象 RealSubject ,设置回调对象为代理对象 ProxySubject ,最后通过 enhancer.create() 方法生成代理对象。通过代理对象调用真实对象的方法,即可执行代理对象和真实对象的方法。
通过上述代码案例,可以看出 Cglib 代理模式的实现方式。Cglib 代理模式的优点是可以代理类,无需真实对象实现接口,同时可以在运行时动态生成代理类,代码量相对较少,并且便于代码的复用。缺点是生成代理类的过程比较耗时,且对于 final 类和 final 方法无法进行代理。

在这里插入图片描述

💕💕 本文由激流原创,首发于CSDN博客,博客主页 https://blog.csdn.net/qq_37967783?spm=1010.2135.3001.5421
💕💕喜欢的话记得点赞收藏啊

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

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

相关文章

qt中c++获取图片qml实时显示的方式1——继承QQuickPaintedItem

通过c opencv获取rtsp视频流&#xff0c;或者视频源&#xff0c;在qml上进行实时视频显示。 一、在QML中通过QQuickPaintedItem动态加载图片 在QML中&#xff0c;可以使用QQuickPaintedItem来创建自定义的可绘制项。通过继承QQuickPaintedItem类&#xff0c;我们可以在QML中动…

这些面试攻略给你2023测试面试带来最强力的支持

在boss和拉钩上投了有几十份简历&#xff0c;其中70%未读状态&#xff0c;30%已读&#xff0c;已读的一半回复要求发送附件简历&#xff0c;然后这周接到面试的有七、八家公司&#xff0c;所以&#xff0c;当前这个大环境真的难 这半个月来&#xff0c;每天安排三到四场面试&a…

自学黑客(网络安全),一般人我劝你还是算了吧(自学网络安全学习路线--第八章 恶意软件概念及防范)【建议收藏】

文章目录 一、自学网络安全学习的误区和陷阱二、学习网络安全的一些前期准备三、自学网络安全学习路线一、恶意软件分类1、分类依据2、获取远程控制权类3、维持远程控制权类4、完成特定业务逻辑类 二、恶意软件运行症状1、查看网络连接2、查看系统进程3、查看隐藏文件 三、恶意…

PACS/RIS医学影像管理系统源码 提供先进图像处理和算法

PACS&#xff08;医学影像存档与通信系统&#xff09;主要应用于医学影像的存储、传输和显示。它可以使医生突破胶片的局限&#xff0c;对病人的影像进行全方位的处理和观察&#xff0c;以便得出更准确的诊断。同时&#xff0c;PACS可以节省大量的胶片&#xff0c;降低成本。医…

定积分与几何应用

定积分与几何应用 何谓定积分&#xff1f; ∫ a b f ( x ) d x \int_a^bf(x)dx ∫ab​f(x)dx需满足 a a a、 b b b有限&#xff08;不是无穷&#xff09;且 f ( x ) f(x) f(x)有界 定积分的计算主要依靠NL公式即牛顿莱布尼茨公式 定积分是否存在于原函数是否存在无关 定积分计…

骑士周游问题及优化

文章和代码已经归档至【Github仓库&#xff1a;https://github.com/timerring/java-tutorial 】或者公众号【AIShareLab】回复 java 也可获取。 文章目录 骑士周游问题算法优化意义经典算法面试题-骑士周游问题马踏棋盘算法介绍 骑士周游问题的解决步骤和思路分析 骑士周游问题…

什么是哈希表

哈希表 目录 哈希表哈希函数哈希碰撞拉链法线性探测法常见的三种哈希结构总结 首先什么是 哈希表&#xff0c;哈希表&#xff08;英文名字为Hash table&#xff0c;国内也有一些算法书籍翻译为散列表&#xff0c;大家看到这两个名称知道都是指hash table就可以了&#xff09;。…

Unity3D:Hierarchy 窗口

推荐&#xff1a;将 NSDT场景编辑器 加入你的3D工具链 3D工具集&#xff1a; NSDT简石数字孪生 Hierarchy 窗口 打开 Unity 新项目时的默认 Hierarchy 窗口视图 Hierarchy 窗口显示场景中的每个游戏对象&#xff0c;如模型、摄像机或预制件。 可以使用 Hierarchy 窗口对场景中…

Nginx | 苹果电脑Mac安装和验证Nginx服务过程记录

common wx&#xff1a;CodingTechWork&#xff0c;一起学习进步。 引言 本文主要总结如何在Mac电脑上进行Nginx服务的安装&#xff0c;重点讲解使用brew命令进行安装和验证的过程及问题记录。 安装步骤 安装过程记录 查看nginx信息 首先使用命令brew info nginx进行本机ng…

网络规划工具

对于各种规模的企业和组织来说&#xff0c;应对安全威胁和可靠的网络性能至关重要。战略性地投资有效的网络监控解决方案可以节省时间和成本&#xff0c;减少停机时间并提高员工的生产力&#xff0c;还可以让管理员专注于重要的事情。重要的是要了解&#xff0c;随着业务的增长…

JAVA大作业——网络在线对战游戏——坦克大战

目录 大作业要求 实机演示 主机环回地址布置连接演示 多人联机对战演示 WASD控制坦克移动和按J键发射炮弹攻击 攻击到敌人后会爆炸并且消灭敌人 按下C键设置IP主机连接 大作业要求 简单的小游戏 要求1&#xff1a;能够实现例如贪吃蛇、坦克大战、俄罗斯方块等小游戏&#x…

红帽:多云和AI时代,开放混合云是最优选择

随着云计算市场群雄割据的格局逐渐定型&#xff0c;混合多云的环境已经成为大势所趋。而近年来AI人工智能技术的高速发展&#xff0c;则进一步为技术创新注入了澎湃动力。 那么问题就来了&#xff1a;在这个多云和AI大行其道的时代&#xff0c;企业应该选择什么样的云平台&…

删除PDF页面的10个操作工具方法分享

PDF被广泛用于各种目的&#xff0c;包括共享学术文件、专业报告&#xff0c;甚至个人文件。然而&#xff0c;有时您可能会发现需要从PDF中删除一些页面。虽然有很多付费软件可供选择&#xff0c;但也有很多免费删除PDF页面的方法。在这篇文章中&#xff0c;我们将讨论10种免费删…

这所广东的985录取平均分387分,复录比高达3.5,单科线55分!

一、学校及专业介绍 中山大学&#xff08;Sun Yat-sen University&#xff09;&#xff0c;简称“中大”&#xff0c;位于广东省&#xff0c;位列国家“双一流”、“985工程”、“211工程”&#xff0c;学校由广州、珠海、深圳三个校区&#xff0c;博士后科研流动站44个&#x…

CentOS7安装部署OpenVidu

1&#xff1a;安装Docker 参考&#xff1a;Centos7 安装 Docker_zzhongcy的博客-CSDN博客 2&#xff1a;安装OpenVidu 2.1、OpenVidu 简介 OpenVidu Server&#xff08;openvidu-server)&#xff1a;是openvidu平台的大脑&#xff0c;负责信号层。Kurento Media Server(kms)…

软件测试技能,JMeter压力测试教程,批量注册测试账号(计数器的使用)(十二)

一、前言 当我们jmeter压测的时候&#xff0c;需要准备一批测试账号&#xff0c;可以先批量注册一些用户&#xff0c;这些用户名称按固定格式 注册的用户不能重复并且需要自增&#xff0c;那么可以使用计数器来实现 二、添加注册请求 我想批量注册100个账号&#xff0c;账号…

【uniapp微信小程序footer】不满一屏固定显示在底部,超出一屏随页面滚动

<template><view class"wrapper"><view class"main">...</view><view class"footer">xx智慧农场</view></view > </template> <style>page {height: 100%;}.wrapper {height: 100%;}.ma…

高德地图的使用

JS API 结合 Vue 使用 高德地图 jsapi 下载、引入 npm add amap/amap-jsapi-loaderimport AMapLoader from amap/amap-jsapi-loader 使用2.0版本的loader需要在window对象下先配置 securityJsCode JS API 安全密钥使用 JS API 使用 script 标签同步加载增加代理服务器设置…

不定长(可变) 位置参数 *args和关键字参数 **kwargs 详解

位置参数&#xff1a; 传参时前面不带 "变量名", 顺序不可变, 按顺序赋给相应的局部变量def test(one,two,three):print(one - two * three)test(1,2,3) def test(one,two,three):print(one - two * three)test(3,2,1) 注意位置参数&#xff0c;需要注意 1 、 不…

STM32外设系列—BH1750

文章目录 一、BH1750简介二、BH1750原理图三、BH1750数据手册3.1 指令集3.2 IIC通信读/写 四、BH1750程序设计4.1 IIC程序4.2 BH1750初始化程序4.3 读取BH1750测量结果4.4 获取光照强度4.5 相关宏定义 五、应用实例六、拓展应用6.1 实时调节LED亮度6.2 实时调整颜色阈值 一、BH…