设计模式四:适配器模式

1、适配器模式的理解

适配器模式可以理解为有两个现成的类Adaptee和Target,它们两个是不能动的,要求必须使用B这个类来实现一个功能,但是A的内容是能复用的,这个时候我们需要编写一个转换器

适配器模式

  • Adaptee:被适配者,现有的接口或者类;
  • Adapter:适配器类,适配器模式的核心,转换作用
  • Target:目标接口或者类

适配器模式的实现步骤

  • 定义目标接口,即客户端所期望的接口。
  • 定义适配器类,继承目标接口并包含一个适配者对象。
  • 在适配器类中实现目标接口的方法,调用适配者对象的相关方法进行适配。
  • 在客户端中使用适配器类进行操作。

适用场景

  • 继承:需要用到别人的类,但是不能修改
  • 多适配者:多个不同的对象,需要让他们具有相同的方法
  • 缺省形式

适配器模式有类适配器和对象适配器两种方式,一般采用前者

2、继承场景

来公司第二天,写一个简单的业务,看到同事写的接口中5个方法有3个正好可以用的,但是还需要另外新增一个,于是我便开始了改造(新增一个方法);提交后同事大发雷霆,谁让你新增的,新增了这个方法,这个接口就失去了本来的意思。。。。。。

我去***,那算了,我还是自己写一个吧,想想怎么能在不懂他的接口前提下,复用一下他的代码,那边使用适配器模式

//同事的接口为被适配者
public interface Adaptee{
    void method1();
    void method2();
    void method3();
    void method4();
    void method5();
}
public class AdapteeImpl implements Adaptee {
    @Override
    public void method1() {
        System.out.println("method1 execute......");
    }

    @Override
    public void method2() {
        System.out.println("method2 execute......");
    }

    @Override
    public void method3() {
        System.out.println("method3 execute......");
    }

    @Override
    public void method4() {
        System.out.println("method4 execute......");
    }

    @Override
    public void method5() {
        System.out.println("method5 execute......");
    }
}

//我需要使用的接口为目标接口
public interface Target{
    void method1();
    void method2();
    void method3();
    void method6();
}
//构建适配器类Adapter
//方式一:类适配器方式
public class Adapter1 extends AdapteeImpl implements Target {
    @Override
    public void method6() {
        System.out.println("method6 execute......");
    }
}

public class Client {
    public static void main(String[] args) {
        Target target = new Adapter1();

        target.method1();
        target.method2();
        target.method3();
        target.method6();
    }
}

//方式二:对象适配器方式
public class Adapter2 implements Target {

    private Adaptee adaptee;

    public Adapter2(Adaptee adaptee) {
        this.adaptee = adaptee;
    }

    @Override
    public void method1() {
        adaptee.method1();
    }

    @Override
    public void method2() {
        adaptee.method2();
    }

    @Override
    public void method3() {
        adaptee.method3();
    }

    @Override
    public void method6() {
        System.out.println("method6 execute......");
    }
}

public class Client {
    public static void main(String[] args) {
        Target target = new Adapter2(new AdapteeImpl());

        target.method1();
        target.method2();
        target.method3();
        target.method6();
    }
}

3、多适配者

多个适配者,适配同一个目标接口,为每一个适配者创建一个适配器

这种是最常用的方式,在springMVC和AOP中都有用到,后面会进行解析

例:新能源汽车的发动机有电能发动机(Electric Motor)和光能发动机(Optical Motor)等,各种发动机的驱动方法不同,例如,电能发动机的驱动方法 electricDrive() 是用电能驱动,而光能发动机的驱动方法 opticalDrive() 是用光能驱动,它们是适配器模式中被访问的适配者。

客户端希望用统一的发动机驱动方法 drive() 访问这两种发动机,所以必须定义一个统一的目标接口 Motor,然后再定义电能适配器(Electric Adapter)和光能适配器(Optical Adapter)去适配这两种发动机。

在这里插入图片描述

package adapter;

//目标:发动机
interface Motor {
    public void drive();
}

//适配者1:电能发动机
class ElectricMotor {
    public void electricDrive() {
        System.out.println("电能发动机驱动汽车!");
    }
}

//适配者2:光能发动机
class OpticalMotor {
    public void opticalDrive() {
        System.out.println("光能发动机驱动汽车!");
    }
}

//电能适配器
class ElectricAdapter implements Motor {
    private ElectricMotor emotor;
    public ElectricAdapter() {
        emotor=new ElectricMotor();
    }
    public void drive() {
        emotor.electricDrive();
    }
}

//光能适配器
class OpticalAdapter implements Motor {
    private OpticalMotor omotor;
    public OpticalAdapter() {
        omotor=new OpticalMotor();
    }
    public void drive() {
        omotor.opticalDrive();
    }
}

//客户端代码
public class MotorAdapterTest {
    public static void main(String[] args) {
        System.out.println("适配器模式测试:");
        Motor motor=(Motor)ReadXML.getObject();
        motor.drive();
    }
}

4、缺省形式

缺省就是对于一个具有很多方法的接口,我没只需要其中几个,不想把所有的方法都实现一遍,可以写一个抽象类作为适配器,再去继承该适配器

public interface Adaptee {
    void model1();
    void model2();
    void model3();
    void model4();
    void model5();
    void model6();
    void model7();
    void model8();
    void model9();
    void model10();
}

public abstract class Adapter implements Adaptee{
    @Override
    public void model1() {}

    @Override
    public void model2() {}

    @Override
    public void model3() {}

    @Override
    public void model4() {}

    @Override
    public void model5() {}

    @Override
    public void model6() {}

    @Override
    public void model7() {}

    @Override
    public void model8() {}

    @Override
    public void model9() {}

    @Override
    public void model10() {}
}

public class Target extends Adapter{
    @Override
    public void model3() {
        System.out.println("model3......");
    }

    @Override
    public void model7() {
        System.out.println("model7......");
    }
}

5、spring中的适配器模式

5.1 SpringMVC
请求处理流程

HandlerAdapter 在 Spring MVC 中使用了适配器模式。HandlerAdapter 主要用于支持不同类型的处理器(如 Controller、HttpRequestHandler 或者 Servlet 等),让它们能够适配统一的请求处理流程。这样,Spring MVC 可以通过一个统一的接口来处理来自各种处理器的请求。在 Spring MVC 的工作流程中,HandlerAdapter 扮演了一个重要角色。以下是其工作原理的简化版:

在这里插入图片描述

  • DispatcherServlet:前端控制器(Front Controller),负责接收所有请求并将其分发给相应的处理程序
  • HandlerMapping:处理器映射器,立请求URL与处理程序之间的映射关系,默认为RequestMappingHandlerMapping(根据@Controller注解和@RequestMapping注解来进行URL与处理程序的映射),可以在Spring配置文件(如XML配置文件或Java配置类)中显式地配置所需的HandlerMapping
  • HandlerAdapter:处理器适配器,通过handlerMapping获取到对应的处理程序handler(controller)后,通过所有注册的handlerAdaptersupports()方法找到对应的适配器来调用,当存在多个合适的HandlerAdapter时,框架会根据一定规则进行判断和选择

  1. 用户发起一个 HTTP 请求到 Spring MVC 应用。
  2. DispatcherServlet 接收到请求后,首先会调用 HandlerMapping,寻找合适的处理器(Handler)来处理这个请求。
  3. 找到合适的处理器后,DispatcherServlet 需要找到一个能够处理这个处理器的 HandlerAdapter。为此,它会遍历所有已注册的 HandlerAdapter,调用它们的 supports 方法,检查它们是否支持当前处理器。
  4. 找到支持当前处理器的 HandlerAdapter 后,DispatcherServlet 会调用该 HandlerAdapterhandle 方法,将请求委托给处理器进行处理。
  5. 处理器处理完请求后,会返回一个 ModelAndView 对象,DispatcherServlet 会将这个对象传递给适当的 ViewResolver,以解析视图并将响应返回给用户。

我们在ControllerServiceMapper中写的业务逻辑,在HandlerAdapter的处理过程中执行

以下是一个简化的 HandlerAdapter 接口示例:

public interface HandlerAdapter {
    boolean supports(Object handler);
    ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
}

Spring MVC 提供了一些内置的 HandlerAdapter 实现,如RequestMappingHandlerAdapterSimpleControllerHandlerAdapterHttpRequestHandlerAdapter 是 Spring MVC 中内置的几个 HandlerAdapter 实现,它们分别用于支持不同类型的处理器。

  1. RequestMappingHandlerAdapter:支持基于注解的处理器,如使用 @Controller@RequestMapping 注解的处理器方法。这是 Spring MVC 中最常用的处理器类型。
  2. SimpleControllerHandlerAdapter:支持实现 org.springframework.web.servlet.mvc.Controller 接口的处理器。这是 Spring MVC 早期版本中的处理器类型,现在已经较少使用。
  3. HttpRequestHandlerAdapter:支持实现 org.springframework.web.HttpRequestHandler 接口的处理器。这种类型的处理器主要用于处理静态资源,如图片、样式表等。

举例:

@Controller
@RequestMapping("/user")
public class UserController {

    @GetMapping("/{id}")
    public String getUserById(@PathVariable("id") Long id, Model model) {
        // 执行业务逻辑
        return "userDetails";
    }
}

在上述例子中有一个controller,当spring接收到请求时,处理过程为:

假设我们使用了默认的配置和注解驱动。

1、首先,前端控制器(DispatcherServlet)会根据请求的 URL 路径来选择合适的 HandlerMapping。在 Spring MVC 中,默认使用的是 RequestMappingHandlerMapping,它会根据 @RequestMapping 注解以及其他相关注解来确定处理程序(handler)与请求路径之间的映射关系。

2、 对于 UserController 中的 getUserById() 方法,使用了 @GetMapping 注解,并指定了路径为 “/{id}”。因此,当客户端发送 GET 请求到 “/user/{id}” 路径时,RequestMappingHandlerMapping 就会匹配到这个处理程序(handler)。

3、 接下来,在执行处理程序之前,前端控制器还需要选择合适的 HandlerAdapter,并将请求委托给它来执行处理程序

4、对于标注有 @GetMapping、@PostMapping 等注解的方法,默认情况下会选择 RequestMappingHandlerAdapter 作为主要的 HandlerAdapter。

5、RequestMappingHandlerAdapter 是一个功能强大且灵活的适配器,能够处理包含模型数据、参数绑定、异常处理等复杂情况。

在上述例子中,当通过 RequestMappingHandlerMapping 匹配到 UserController 的 getUserById() 方法后,前端控制器就会选择 RequestMappingHandlerAdapter 来执行这个处理程序,并传递相应的请求参数和模型数据给该方法。

在 Spring MVC 中,前端控制器(DispatcherServlet)会根据请求路径和方法来选择合适的 HandlerAdapter。

选择后,HandlerAdapter 将接收到的请求参数、模型数据等信息传递给相应的处理程序(业务逻辑),并执行该处理程序。

HandlerAdapter 根据具体的处理程序类型来确定调用哪个方法,以及如何将请求数据传递给该方法。

不同类型的处理程序可能有不同的要求和处理方式。 例如,在使用注解配置的方法作为处理程序时,默认情况下会选择 RequestMappingHandlerAdapter。

RequestMappingHandlerAdapter 会根据注解中定义的规则,将请求参数、路径变量、请求体内容等绑定到方法的入参上,并调用该方法执行业务逻辑。它还能够通过模型对象(Model)来向视图传递数据。

可以说 HandlerAdapter 是负责将请求数据传递给我们自己编写的业务逻辑处理程序,并执行其中定义的方法。它是框架与业务代码之间进行通信和协调的重要环节。

自定义handlerAdapter

通常情况下,Spring MVC 默认提供的 HandlerAdapters 是能够满足大多数应用场景的,并且能够处理各种类型的处理程序(handler)。

在某些特殊情况下,可能需要自定义 HandlerAdapter 来满足特定的需求。以下是一些需要自定义 HandlerAdapter 的情况:

  1. 需要支持新的处理程序类型:如果你使用了自定义的处理程序类型,而该类型不属于 Spring MVC 默认支持的类型,那么你可以编写自己的 HandlerAdapter 来支持该类型。

  2. 特定的请求/响应方式:如果你想要处理一种不常见或非标准的请求/响应方式,例如 WebSocket、SSE(服务器发送事件)等,你可能需要编写一个适配器来处理这些方式。

  3. 定制化业务逻辑:如果你有特殊的业务需求,需要在执行业务逻辑之前或之后添加额外的逻辑操作,例如权限校验、日志记录等,你可以编写一个自定义 HandlerAdapter 来扩展框架提供的功能。

  4. 性能优化:如果你对性能有极高要求,并希望通过优化执行过程来提升系统性能,可以根据具体场景编写一个更高效的 HandlerAdapter 来替换默认实现。

总之,在需要与 Spring MVC 框架进行更深度集成、满足特定需求或优化性能时,可以考虑自定义 HandlerAdapter。但在大多数情况下,默认提供的 HandlerAdapters 能够满足开发需求。

handlerAdapter的适配器模式

可以看到处理器的类型不同,有多重实现方式,那么调用方式就不是确定的,如果需要直接调用 Controller 方法,需要调用的时候就得不断地使用 if else 来进行判断是哪一种子类然后执行。那么如果后面要扩展 Controller, 就得修改原来的代码,这样违背了 OCP 原则

在这里插入图片描述

下面手写一下handlerAdapter的选择流程

//controller类,我们自己写的逻辑,即handler
public interface Controller {
    
}

public class AnnotationController implements Controller{
    public void doAnnotationHandler() {
        System.out.println("annotation...");
    }
}

public class HttpController implements Controller{
    public void doHttpHandler() {
        System.out.println("http...");
    }
}

public class SimpleController implements Controller{
    public void doSimpleHandler() {
        System.out.println("simple...");
    }
}
//handlerAdapter类 处理器适配器
//通过handlermapping获取到对应的handler后,再查找对应的处理器适配器调用对应方法
public interface HandlerAdapter {
    boolean supports(Object handler);

    void handle(Object handler);
}

public class AnnotationHandlerAdapter implements HandlerAdapter{
    @Override
    public boolean supports(Object handler) {
        // TODO Auto-generated method stub
        return (handler instanceof AnnotationController);
    }

    @Override
    public void handle(Object handler) {
        // TODO Auto-generated method stub
        ((AnnotationController)handler).doAnnotationHandler();
    }
}

public class HttpHandlerAdapter implements HandlerAdapter {
    @Override
    public boolean supports(Object handler) {
        // TODO Auto-generated method stub
        return (handler instanceof HttpController);
    }

    @Override
    public void handle(Object handler) {
        // TODO Auto-generated method stub
        ((HttpController)handler).doHttpHandler();
    }
}

public class SimpleHandlerAdapter implements HandlerAdapter{
    @Override
    public boolean supports(Object handler) {
        // TODO Auto-generated method stub
        return (handler instanceof SimpleController);
    }

    @Override
    public void handle(Object handler) {
        // TODO Auto-generated method stub
        ((SimpleController)handler).doSimpleHandler();
    }
}
//DispatcherServlet类 执行整体逻辑
public class DispatchServlet {
    public static List<HandlerAdapter> handlerAdapters = new ArrayList<HandlerAdapter>();

    //注内置的处理器适配器,也可以自定义,然后注册到DispatcherServlet类中
    public DispatchServlet() {
        handlerAdapters.add(new AnnotationHandlerAdapter());
        handlerAdapters.add(new HttpHandlerAdapter());
        handlerAdapters.add(new SimpleHandlerAdapter());
    }

    public void doDispatch() {

        /*
         *   1、这里用来调用handlermapping获取对应的controller(handler)
         *   springmvc中默认使用的是 RequestMappingHandlerMapping
         */
        AnnotationController annotationController = new AnnotationController();

        //2、通过controller(handler)选择对应的handlerAdapter
        HandlerAdapter handlerAdapter = getHandler(annotationController);

        //3、调用对应处理程序(controller的方法),处理请求
        handlerAdapter.handle(annotationController);

    }

    public HandlerAdapter getHandler(Controller controller) {
        for (HandlerAdapter handlerAdapter : handlerAdapters) {
            if(handlerAdapter.supports(controller)) {
                return handlerAdapter;
            }
        }
        return null;
    }
}
//客户端
public class Client {
    public static void main(String[] args) {
        new DispatchServlet().doDispatch();
    }
}
自定义适配器

要自定义一个 HandlerAdapter,你需要实现 org.springframework.web.servlet.HandlerAdapter 接口,并提供对你的自定义处理器的支持。下面是一个简单的自定义 HandlerAdapter 示例:

首先,创建一个自定义处理器:

public class CustomHandler {
    public String handleRequest() {
        return "Hello, CustomHandler!";
    }
}

接着,实现一个自定义的 HandlerAdapter

import org.springframework.web.servlet.HandlerAdapter;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class CustomHandlerAdapter implements HandlerAdapter {
    @Override
    public boolean supports(Object handler) {
        return handler instanceof CustomHandler;
    }

    @Override
    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        CustomHandler customHandler = (CustomHandler) handler;
        String result = customHandler.handleRequest();
        return new ModelAndView("customView", "message", result);
    }

    @Override
    public long getLastModified(HttpServletRequest request, Object handler) {
        return -1;
    }
}

要在 Spring MVC 应用中使用这个自定义的 HandlerAdapter,你需要将其注册到 DispatcherServlet 中。在基于 Java 配置的应用中,你可以这样做:

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerAdapter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
    @Override
    protected void addAdapters(List<HandlerAdapter> adapters) {
        adapters.add(new CustomHandlerAdapter());
        super.addAdapters(adapters);
    }
}

这样,你的自定义 HandlerAdapter 就会在 Spring MVC 应用中生效,并能处理 CustomHandler 类型的处理器。

5.2 AOP

在Spring的Aop中,使用Advice(通知)来增强被代理类的功能,Advice的类型有:BeforeAdvice、AfterReturningAdvice、ThreowSadvice。

每种Advice都有对应的拦截器,MethodBeforeAdviceInterceptor、AfterReturningAdviceInterceptor、ThrowsAdviceInterceptor。

各种不同类型的Interceptor,通过适配器统一对外提供接口,如下类图所示:client —> target —> adapter —> interceptor —> advice。最终调用不同的advice来实现被代理类的增强
原理springmvc类似
在这里插入图片描述

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

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

相关文章

Java Web(一)--介绍

Java Web 技术体系图 三大组成部分&#xff1a; 前端&#xff1a; 前端开发技术工具包括三要素&#xff1a;HTML、CSS 和 JavaScript&#xff1b;其他高级的前端框架&#xff0c;如bootstrap、jquery&#xff0c;VUE 等。 后端&#xff1a; 后端开发技术工具主要有&am…

剑指offer刷题笔记-链表

少年何妨梦摘星 敢挽桑弓射玉衡 解决与链表相关的问题总是有大量的指针操作&#xff0c;而指针操作的代码总是容易出错的。很多面试官喜欢出与链表相关的问题&#xff0c;就是想通过指针操作来考察应聘者的编码功底。 题目链接来自于 AcWing 、Leetcode&#xff08;LCR&#xf…

燃气企业须知 :智慧燃气信息化管理平台的作用 ?

关键词&#xff1a;智慧燃气、燃气信息化、智慧燃气平台、智慧燃气建设、智慧燃气解决方案 智慧燃气信息化管理平台通过城市输气管网作为主要基础&#xff0c;各个终端用户进行协调&#xff0c;依托信息化数据进行管理&#xff0c;从而让整个工作环节流程达到高效智能优势。通…

【LeetCode】树的BFS(层序遍历)精选6题

目录 1. N 叉树的层序遍历&#xff08;中等&#xff09; 2. 二叉树的锯齿形层序遍历&#xff08;中等&#xff09; 3. 二叉树的最大宽度&#xff08;中等&#xff09; 4. 在每个树行中找最大值&#xff08;中等&#xff09; 5. 找树左下角的值&#xff08;中等&#xff09…

leetcode(动态规划)53.最大子数组和(C++详细解释)DAY12

文章目录 1.题目示例提示 2.解答思路3.实现代码结果 4.总结 1.题目 给你一个整数数组 nums &#xff0c;请你找出一个具有最大和的连续子数组&#xff08;子数组最少包含一个元素&#xff09;&#xff0c;返回其最大和。 子数组 是数组中的一个连续部分。 示例 提示 2.解答思…

数论 - 博弈论(Nim游戏)

文章目录 前言一、Nim游戏1.题目描述输入格式输出格式数据范围输入样例&#xff1a;输出样例&#xff1a; 2.算法 二、台阶-Nim游戏1.题目描述输入格式输出格式数据范围输入样例&#xff1a;输出样例&#xff1a; 2.算法 三、集合-Nim游戏1.题目描述输入格式输出格式数据范围输…

vue使用Nprogress进度条功能实现

下图中的这种顶部进度条是非常常见的&#xff0c;在vue项目中有对应的插件&#xff1a;Nprogress。 实现效果&#xff1a; csdn也在使用&#xff1a; 或者这样自己使用 1、安装 NProgress可以通过npm安装。 npm install --save nprogress 注意此处的--save等同于-s,就是将…

echats 时间直方图示例

需求背景 某订单有N个定时任务&#xff0c;每个任务的执行时间已经确定&#xff0c;希望直观的查看该订单的任务执行趋势 查询SQL&#xff1a; select UNIX_TIMESTAMP(DATE_FORMAT(exec_time,%Y-%m-%d %H:%i)) execTime, count(*) from order_detail_task where order_no 2…

【C++】vector模拟实现+迭代器失效

vector模拟实现 成员变量定义默认成员函数构造函数 迭代器范围for、对象类型匹配原则 容量操作sizeemptycapacityreserve成员变量未更新memcpy值拷贝 resize内置类型的构造函数 数据访问frontbackoperator[ ] 数据修改操作push_backpop_backswapclearinsertpos位置未更新无返回…

el-button 选择与非选择按钮批量处理

el-button 选择与非选择按钮批量处理 <el-button v-for"(voyage,i) in data[voyages][nowVoyage]":key"i"class"c-work-bts"type"primary":plain"nowWorkSpace!i"click"chooseWorkSpace(i)"size"small&qu…

C#快速配置NLog日志使用

首先我们需要在Nuget中安装Nlog和Nlog-Schema。 添加配置文件&#xff1a;NLog.config <?xml version"1.0" encoding"utf-8" ?> <nlog xmlns"http://www.nlog-project.org/schemas/NLog.xsd"xmlns:xsi"http://www.w3.org/2001…

CSS弹性布局

CSS弹性布局 一、概念 ​ 弹性盒子是 CSS3 的一种新的布局模式。 ​ CSS3 弹性盒&#xff08; Flexible Box 或 flexbox&#xff09;&#xff0c;是一种当页面需要适应不同的屏幕大小以及设备类型时确保元素拥有恰当的行为的布局方式。 ​ 引入弹性盒布局模型的目的是提供一…

山西电力市场日前价格预测【2024-02-21】

日前价格预测 预测说明&#xff1a; 如上图所示&#xff0c;预测明日&#xff08;2024-02-21&#xff09;山西电力市场全天平均日前电价为470.29元/MWh。其中&#xff0c;最高日前电价为654.81元/MWh&#xff0c;预计出现在18:45。最低日前电价为355.63元/MWh&#xff0c;预计…

将Windows的系统日志自动收集并且转发到syslog服务器,百试百灵

将windows的系统日志自动收集并且转发到syslog服务器&#xff0c;百试百灵* **使用*Evtsys工具&#xff0c;他会自动收集windows系统日志&#xff0c;然后发送到syslog服务器&#xff0c;并且不乱码 下载链接&#xff1a;百度云永久链接 链接&#xff1a;https://pan.baidu.co…

D9741——用于也收路像机和笔记本电的等设备上的直流转换器。在便携式的仪器设备上。低电压输入时误操作保护电路, 定时闩锁、短路保护电路等功能

D9741是一块脉宽调制方三用于也收路像机和笔记本电的等设备上的直流转换器。在便携式的仪器设备上。 主要特点: 高精度基准电路 定时门锁、短路保护电路 低电压输入时误操作保护电路 输出基准电压(2.5V 超过工作范围能进行自动校正 封装形式: SOP16 应用: 电视摄像机 笔记本电…

5个顶级开源法学硕士大型语言模型 (LLM)

5个顶级开源法学硕士大型语言模型 (LLM)。 在快速发展的人工智能 (AI) 世界中&#xff0c;大型语言模型 (LLM) 已成为推动创新并重塑我们与技术交互方式的基石。 随着这些模型变得越来越复杂&#xff0c;人们越来越重视对它们的访问的民主化。 尤其是开源模型&#xff0c;在这…

算法面试八股文『 模型详解篇 』

说在前面 这是本系列的第二篇博客&#xff0c;主要是整理了一些经典模型的原理和结构&#xff0c;面试有时候也会问到这些模型的细节&#xff0c;因此都是需要十分熟悉的。光看原理还不够&#xff0c;最好是能用代码试着复现&#xff0c;可以看看李沐老师深度学习的教材&#…

线程池:优化多线程管理的利器

引言 同步和异步想必各位都有了解&#xff0c;同步简单来说就是一件事做完再去做下一件&#xff1b;异步则是不用等一件事做完&#xff0c;就可以去做另一件事&#xff0c;当一件事完成后可以收到对应的通知&#xff1b;异步一般应用于一些耗时较长的操作&#xff0c;比如大型…

量子计算:数据安全难题

当今数字技术面临的最大挑战之一是安全系统和数据。为此&#xff0c;人们设计了复杂的算法来加密数据并通过称为对称加密的框架来保护数据。虽然这已被证明是成功的&#xff0c;但量子计算的进步&#xff08;利用量子力学比传统计算机更快地解决复杂问题&#xff09;可能会彻底…

Flink的单元测试介绍及示例

本文详细的介绍了Flink的单元测试&#xff0c;分为有状态、无状态以及作业的测试&#xff0c;特别是针对无状态的单元测试给出了常见的使用示例。 本文除了maven依赖外&#xff0c;没有其他依赖。 一、Flink测试概述 Apache Flink 同样提供了在测试金字塔的多个级别上测试应用程…