适配器模式详解:解决接口不兼容问题的灵活设计模式

适配器模式

目录

  • 1 概述
  • 2 主要角色
  • 3 适配器模式的两种实现方式
    • 类适配器
      • 3.1.1 示例
      • 3.1.2 Mermaid图
    • 对象适配器
      • 3.2.1 示例
      • 3.2.2 MerMaid类图
    • 双向适配器模式
      • 3.3.1 示例
        • 接口实现
        • 具体实现
      • 3.3.2 MerMaid 类图
    • 缺省适配器模式
      • 3.4.1 示例
      • 3.4.2 Mermaid类图
  • 4 适用场景
    • 具体场景示例
  • 5 适配器模式的优缺点
    • 5.1 优点
    • 5.2 缺点
  • 6 .NET 中的适配器模式案例
    • DataAdapter:
    • HttpClient 和 HttpMessageHandler:
  • 7 适配器模式与其它模式的区别
  • 8 总结
  • 9 参考

1 概述

💡在软件开发中,基本上任何问题都可以通过增加一个中间层来解决。适配器模式其实就是一个中间层。综上,适配器模式起着转化/委托的作用,将一种接口转化为另一种符合需求的接口。1

  1. 适配器模式是一种结构型设计模式​。结构型设计模式关注如何组合类和对象以形成更大的结构,旨在简化设计并提高系统的灵活性和可复用性。它分为类结构型模式(通过继承)和对象结构型模式(通过组合或聚合)。
  2. 适配器模式可以将一个类的接口和另一个类的接口匹配起来,从而使原本因接口不匹配的类可以协同工作,并且无须修改原来的适配者接口和抽象目标类接口。
  3. 在需要集成旧代码、统一接口或处理不同数据源时。通过适配器模式,可以实现代码的复用、解耦和灵活性。在实际开发中,合理使用适配器模式可以显著提高代码的可维护性和扩展性。

2 主要角色

  1. 目标接口(Target)
    • 这是客户端所期待的接口,定义了客户端需要的操作。
  2. 适配器(Adapter)
    • 适配器的主要职责是将现有类的接口转换为目标接口所期望的格式。
    • 适配器充当了目标接口和现有类之间的转换器。它实现了目标接口,并在内部使用现有类的实例来完成实际的操作。
  3. 现有类(Adaptee)
    • 现有类是需要被适配的类,它已经存在并且具有某些有用的功能,但其接口与客户端所期望的目标接口不兼容。
implements
uses
«interface»
Target目标
+request()
Adapter适配器
-adaptee: Adaptee
+request()
Adaptee适配者
+specificRequest()

3 适配器模式的两种实现方式

根据适配器类与适配者类的关系不同,适配器模式可分为对象适配器模式类适配器模式两种。

在类适配器模式中,适配器与适配者之间是继承(或实现)关系。

在对象适配器模式中,适配器与适配者之间是关联关系;

在实际开发中,对象适配器模式的使用频率更高。

3.1 类适配器

  • 实现:通过继承现有类(Adaptee)并实现目标接口(Target)来实现适配。适配器与适配者之间是继承(或实现)关系。
  • 优点:可以重写现有类的方法来改变其行为,
  • 缺点:由于继承关系,适配器类会继承现有类的所有方法,可能会导致类的膨胀。并且很多语言并不支持多继承,一个类只能继承一个父类,也就只能适配一个Adaptee。
  • 限制:这种方式在某些编程语言中可能会受到多重继承的限制。

3.1.1 示例

  • Target
    // 目标接口
    public interface IMediaPlayer
    {void Play(string audioType, string fileName);
    }
    
  • Adaptee
    // 现有类
    public class AdvancedMediaPlayer
    {public void PlayVlc(string fileName){// 播放VLC文件的逻辑}public void PlayMp4(string fileName){// 播放MP4文件的逻辑}
    }
    
  • Adapter
    
    // 类适配器
    public class MediaAdapter : AdvancedMediaPlayer, IMediaPlayer
    {private string audioType;public MediaAdapter(string audioType){this.audioType = audioType;}public void Play(string audioType, string fileName){if (audioType.Equals("vlc", StringComparison.OrdinalIgnoreCase)){PlayVlc(fileName);}else if (audioType.Equals("mp4", StringComparison.OrdinalIgnoreCase)){PlayMp4(fileName);}}
    }
    
  • Client
     var vlcmediaPlayer = new MediaAdapter("vlc");vlcmediaPlayer.Play("SampleVideo.vlc");var mp4MediaPlayer = new MediaAdapter("mp4");mp4MediaPlayer.Play("SampleVideo.mp4");

3.1.2 Mermaid图

inheritance
implements
«Interface»
IMediaPlayer
+void Play(string audioType, string fileName)
AdvancedMediaPlayer
+void PlayVlc(string fileName)
+void PlayMp4(string fileName)
MediaAdapter
-string audioType
+MediaAdapter(string audioType)
+void Play(string audioType, string fileName)

3.2 对象适配器

  • 实现:通过在适配器类内部持有一个现有类(Adaptee)的实例,并实现目标接口(Target)来实现适配。适配器和现有类是关联关系。
  • 优点:更加灵活,因为它不依赖于继承,可以适配多个不同的现有类;可以很容易地更换现有类的实现;
  • 缺点:无法重写现有类的方法

3.2.1 示例

  • Target
    // 目标接口
    public interface ITarget
    {void Request();
    }
    
  • Adaptee
    // 现有类
    public class Adaptee
    {public void SpecificRequest(){Console.WriteLine("Adaptee.SpecificRequest()");}
    } 
    
  • Adapter
    // 对象适配器
    public class Adapter : ITarget
    {private Adaptee adaptee;public Adapter(Adaptee adaptee){this.adaptee = adaptee;}public void Request(){adaptee.SpecificRequest();}
    }
    
  • Client
    var adaptee = new Adaptee();
    var objectAdapter = new Adapter(adaptee);
    objectAdapter.Request();
    

3.2.2 MerMaid类图

implements
association
«Interface»
ITarget
+void Request()
Adaptee
+void SpecificRequest()
Adapter
-Adaptee adaptee
+Adapter(Adaptee adaptee)
+void Request()

3.3 双向适配器模式

  • 目标:双向适配器模式允许两个不兼容的接口相互适配,使得它们可以互相调用对方的方法。
  • 实现:在适配器类中,同时包含对目标类和适配者类的引用,适配者可以通过它调用目标类中的方法,目标类也可以通过它调用适配者类中的方法。
  • 优点:可以实现两个系统的双向兼容
  • 缺点:适配器类的实现可能会比较复杂,需要同时处理两个接口的适配逻辑。
  • 场景:适用于需要双向交互的场景,例如在两个不同的系统或模块之间进行数据交换和通信时,可以让它们无缝地协同工作。

3.3.1 示例

假设有一个智能窗帘和一个智能温控器,

智能窗帘可以通过调用OpenCurtainCloseCurtain方法来控制开合,

智能温控器可以通过调用IncreaseTemperatureDecreaseTemperature方法来调节温度。

现希望智能窗帘能够根据温度自动开合,同时智能温控器也能根据窗帘的状态调整温度,以实现更智能的家居环境控制。

  • Adaptee
    接口实现
    // 智能窗帘接口
    public interface ISmartCurtain
    {void OpenCurtain();void CloseCurtain();
    }// 智能温控器接口
    public interface ISmartThermostat
    {void IncreaseTemperature();void DecreaseTemperature();
    }
    
    具体实现
    // 智能窗帘实现类
    public class SmartCurtain : ISmartCurtain
    {public void OpenCurtain(){Console.WriteLine("智能窗帘打开");}public void CloseCurtain(){Console.WriteLine("智能窗帘关闭");}
    }// 智能温控器实现类
    public class SmartThermostat : ISmartThermostat
    {public void IncreaseTemperature(){Console.WriteLine("智能温控器升温");}public void DecreaseTemperature(){Console.WriteLine("智能温控器降温");}
    }
    
  • Adapter
    public class SmartHomeAdapter : ISmartCurtain, ISmartThermostat
    {private ISmartCurtain smartCurtain;private ISmartThermostat smartThermostat;public ISmartCurtain SmartCurtain { set => smartCurtain = value; }public ISmartThermostat SmartThermostat { set => smartThermostat = value; }public void OpenCurtain(){Console.Write("根据温度自动 ");smartCurtain.OpenCurtain();smartThermostat.DecreaseTemperature(); // 窗帘打开时,适当降温}public void CloseCurtain(){Console.Write("根据温度自动 ");smartCurtain.CloseCurtain();smartThermostat.IncreaseTemperature(); // 窗帘关闭时,适当升温}public void IncreaseTemperature(){Console.Write("根据窗帘状态自动 ");smartThermostat.IncreaseTemperature();smartCurtain.CloseCurtain(); // 升温时,关闭窗帘以保持温度}public void DecreaseTemperature(){Console.Write("根据窗帘状态自动 ");smartThermostat.DecreaseTemperature();smartCurtain.OpenCurtain(); // 降温时,打开窗帘以促进空气流通}
    }
    
  • Client
    public class Program
    {public static void Main(){ISmartCurtain smartCurtain = new SmartCurtain();ISmartThermostat smartThermostat = new SmartThermostat();SmartHomeAdapter adapter = new SmartHomeAdapter();adapter.SmartCurtain = smartCurtain;adapter.SmartThermostat = smartThermostat;// 根据温度自动控制窗帘和温控器ISmartCurtain curtainAdapter = adapter;curtainAdapter.OpenCurtain(); // 根据温度自动打开窗帘并适当降温curtainAdapter.CloseCurtain(); // 根据温度自动关闭窗帘并适当升温// 根据窗帘状态自动调整温度ISmartThermostat thermostatAdapter = adapter;thermostatAdapter.IncreaseTemperature(); // 根据窗帘状态自动升温并关闭窗帘thermostatAdapter.DecreaseTemperature(); // 根据窗帘状态自动降温并打开窗帘}
    }
    

3.3.2 MerMaid 类图

SmartCurtain
1
SmartThermostat
1
«Interface»
ISmartCurtain
+OpenCurtain()
+CloseCurtain()
«Interface»
ISmartThermostat
+IncreaseTemperature()
+DecreaseTemperature()
SmartCurtain
+OpenCurtain()
+CloseCurtain()
SmartThermostat
+IncreaseTemperature()
+DecreaseTemperature()
SmartHomeAdapter
+OpenCurtain()
+CloseCurtain()
+IncreaseTemperature()
+DecreaseTemperature()

3.4 缺省适配器模式

  • 目标:适用于接口中有多个方法,但客户端只需要使用其中部分方法的情况。
  • 实现:通过创建一个抽象类来实现接口,并为接口中的每个方法提供一个默认的空实现,具体子类只需重写需要使用的方法,而不需要实现接口中的所有方法。
  • 这种模式适用于接口中有多个方法,但大多数方法在某些情况下不需要实现的场景。它可以简化适配器类的实现,避免了实现大量空方法的繁琐。
  • 优点:可以减少代码冗余,提高开发效率
  • 缺点:可能会隐藏一些需要实现的方法,导致子类开发者忘记实现某些重要的方法。

3.4.1 示例

  • Target
    // 目标接口
    public interface IDevice
    {void PowerOn();void PowerOff();void Reset();void Upgrade();
    }
    
  • Adapter
    // 缺省适配器
    public abstract class DefaultDeviceAdapter : IDevice
    {public virtual void PowerOn(){// 默认空实现}public virtual void PowerOff(){// 默认空实现}public virtual void Reset(){// 默认空实现}public virtual void Upgrade(){// 默认空实现}
    }// 具体适配器类
    public class ConcreteDeviceAdapter : DefaultDeviceAdapter
    {public override void PowerOn(){Console.WriteLine("设备开机");}public override void PowerOff(){Console.WriteLine("设备关机");}
    }
    
  • Client
    IDevice device = new ConcreteDeviceAdapter();
    device.PowerOn();  // 输出:设备开机
    device.PowerOff();  // 输出:设备关机
    

3.4.2 Mermaid类图

implements
inheritance
«interface»
IDevice
+void PowerOn()
+void PowerOff()
+void Reset()
+void Upgrade()
«abstract»
DefaultDeviceAdapter
+virtual void PowerOn()
+virtual void PowerOff()
+virtual void Reset()
+virtual void Upgrade()
ConcreteDeviceAdapter
+override void PowerOn()
+override void PowerOff()

4 适用场景

适配器模式主要用于解决接口不兼容的问题,使得原本无法协同工作的类或系统能够顺利交互。以下是适配器模式适用的主要场景:

  1. 兼容性问题导向
    • 接口不匹配是核心痛点:无论是第三方库、旧代码、外部系统,还是不同硬件设备等,场景中都存在接口不一致的问题。
    • 涉及不同系统或组件的交互:场景都围绕着不同系统、组件或模块之间的协同工作。
  2. 复用与保留需求
    • 对已有资源的复用:在复用旧代码、逐步重构系统等场景中,强调对已有代码或模块的再利用。
    • 保留旧接口兼容性:在接口升级场景中,需要考虑到旧版本客户端的兼容性。适配器可以作为中间层,将新接口的特性适配到旧接口上,确保旧客户端仍能正常调用服务。
  3. 统一与转换功能
    • 统一接口标准:多个类的接口统一、跨平台开发中API接口统一等场景,目的是将分散的、不一致的接口整合为一个统一的标准。这样可以简化系统的调用逻辑,提高代码的可维护性和可扩展性。
    • 数据格式转换:支持多种数据格式的场景中,适配器承担着数据格式转换的任务。

具体场景示例

  1. 集成第三方库或组件:适配器模式用于解决系统与第三方库接口不兼容的问题,如支付网关接口转换。

  2. 复用旧代码:适配器模式允许在不修改旧代码的情况下,将其接口适配到新系统需求,如旧日志记录类适配新接口。

  3. 统一多个类的接口:适配器模式可将多个功能相似但接口不一致的类统一为一致接口,如多种数据库操作接口统一。

  4. 与外部系统交互:适配器模式用于与接口不兼容的外部系统交互,如物联网应用中不同硬件设备协议的转换。

  5. 测试驱动开发(TDD):适配器模式可模拟不兼容的依赖项行为,如测试中模拟外部服务的行为。

    例如 OrderProcessor,它依赖于一个外部服务 PaymentService 来处理支付。

    PaymentService 是一个第三方服务,它的接口可能比较复杂,或者它的调用可能会产生副作用(如真实的支付操作)。

    在测试 OrderProcessor 时,并不希望真正调用 PaymentService,此时就可以使用适配器模式,写一个Mock测试实现IPaymentService,模拟支持成功的行为,,以便专注于测试 OrderProcessor 的逻辑。

  6. 支持多种数据格式:适配器模式可将不同数据格式转换为统一接口,如从JSON、XML、数据库等数据源读取数据。

  7. 逐步重构系统:适配器模式用于新旧模块接口不一致时的协同工作,如单体应用拆分为微服务时的接口适配。

  8. 跨平台开发:适配器模式用于统一不同平台的API接口,如跨平台文件操作工具的开发。

  9. 硬件抽象:适配器模式用于统一多种硬件设备的接口,如支持多种品牌打印机的驱动系统。

  10. 接口升级:适配器模式用于在接口升级时保留旧接口的兼容性,如API升级时适配旧版本客户端。

5 适配器模式的优缺点

5.1 优点

  1. 提高类的复用性
    • 现有类可以被复用,而不需要修改其源代码。适配器模式通过创建一个新的适配器类来适配现有类,使得现有类可以在不同的系统或模块中被复用。
  2. 降低类之间的耦合度
    • 客户端与现有类之间的耦合度降低。客户端只需要与适配器的目标接口交互,而不需要直接与现有类的接口打交道。这样,即使现有类的实现发生变化,只要适配器的目标接口保持不变,客户端就不需要修改。
  3. 增加系统的灵活性和扩展性
    • 系统可以更容易地添加新的适配器来适配新的现有类,而不需要修改客户端代码。例如,原本只支持手机号登录,现需要支持微信、邮箱、GitHub等多种登录方式,虽然登录形式丰富,但是登录后的处理逻辑可以不必改,只需要引用适配器模式,使其兼容并支持多种登录模式。

5.2 缺点

  1. 增加系统的复杂性
    • 适配器模式会增加系统的类的数量。每个适配器都是一个单独的类,这可能会使系统的结构变得复杂。
  2. 可能会导致性能问题
    • 适配器模式可能会引入额外的性能开销。因为适配器需要在客户端和现有类之间进行转换,这可能会导致一些额外的函数调用和数据转换操作。例如,在一个性能敏感的实时系统中,适配器的转换操作可能会对系统的性能产生影响。如果适配器的实现不够高效,可能会导致系统的响应时间变长,从而影响用户体验。

6 .NET 中的适配器模式案例

6.1 DataAdapter

  • 在 ADO.NET 中,DataAdapter(如 SqlDataAdapterOleDbDataAdapter)是一个典型的适配器模式应用。
  • 它将不同数据库(如 SQL Server、Oracle、Access)的操作接口适配到统一的 DataSet 接口。
public void DataAdapterDemoMethod()
{string connectionString = "connection_string";string query = "SELECT * FROM Customers";using (SqlConnection connection = new SqlConnection(connectionString)){SqlDataAdapter adapter = new SqlDataAdapter(query, connection);DataSet dataSet = new DataSet();// 填充 DataSetadapter.Fill(dataSet, "Customers");// 访问 DataSet 中的数据foreach (DataRow row in dataSet.Tables["Customers"].Rows){Console.WriteLine(row["CustomerName"]);}}
}

6.2 HttpClientHttpMessageHandler

  • 在 .NET 的 HTTP 客户端库中,HttpClient 使用 HttpMessageHandler 来处理 HTTP 请求。
  • 你可以通过适配器模式自定义 HttpMessageHandler,以适配不同的 HTTP 请求处理逻辑。
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;class CustomHandler : DelegatingHandler
{protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken){// 在发送请求之前可以添加自定义逻辑Console.WriteLine("Request sent to: " + request.RequestUri);// 继续处理请求HttpResponseMessage response = await base.SendAsync(request, cancellationToken);// 在收到响应之后可以添加自定义逻辑Console.WriteLine("Response received with status code: " + response.StatusCode);return response;}
}class Program
{static async Task Main(){HttpClient client = new HttpClient(new CustomHandler());HttpResponseMessage response = await client.GetAsync("https://jsonplaceholder.typicode.com/posts/1");if (response.IsSuccessStatusCode){string content = await response.Content.ReadAsStringAsync();Console.WriteLine(content);}}
}

7 适配器模式与其它模式的区别

这一部分等更新了其他设计模式的内容,再进行更新。

8 总结

适配器模式的核心思想是将一个接口转换为另一个接口,使得原本不兼容的接口能够协同工作。它的主要优点是:

  • 解耦: 将客户端代码与具体实现解耦。
  • 复用: 可以复用现有的类或组件,而无需修改其代码。
  • 灵活性: 可以轻松支持新的接口或实现。

适配器模式也不应滥用。如果接口本身设计合理,或者可以通过重构直接统一接口,那么就不需要使用适配器模式。

9 参考

  1. 《设计模式的艺术》——刘伟

  1. 《设计模式就该这样学: 基于经典框架源码和真实业务场景》——谭勇德 ↩︎

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Linux系统】Ext系列磁盘文件系统二:引入文件系统(续篇)

inode 和 block 的映射 该博文中有详细解释&#xff1a;【Linux系统】inode 和 block 的映射原理 目录与文件名 这里有几个问题&#xff1a; 问题一&#xff1a; 我们访问文件&#xff0c;都是用的文件名&#xff0c;没用过 inode 号啊&#xff1f; 之前总是说可以通过一个…

[计算机网络]一. 计算机网络概论第一部分

作者申明&#xff1a;作者所有文章借助了各个渠道的图片视频以及资料&#xff0c;在此致谢。作者所有文章不用于盈利&#xff0c;只是用于个人学习。 1.0推荐动画 【网络】半小时看懂<计算机网络>_哔哩哔哩_bilibili 1.1计算机网络在信息时代的作用 在当今信息时代&…

Python操作Excel——openpyxl使用笔记(2)

2. 操作工作表 前面提到一个工作簿中会有一个或者多个工作表&#xff0c;当前使用的工作表被称作活动工作表&#xff0c;这里展开介绍一下对于工作表的一些操作。 2.1 枚举所有工作表 使用for循环可以很方便的遍历每个工作表&#xff1a; import openpyxl wb openpyxl.o…

Social LSTM:Human Trajectory Prediction in Crowded Spaces | 文献翻译

概要 行人遵循不同轨迹以避免障碍物和容纳同行者。任何在这种场景中巡航的自动驾驶车辆都需要能够遇见行人的未来位置并相应地调整其路线以避免碰撞。轨迹预测问题能够被看作一个顺序生成任务&#xff0c;其中我们对基于行人过去的位置预测其未来的轨迹感兴趣。根据最近RNN&am…

从零开始:Gitee 仓库创建与 Git 配置指南

引言 Git 是一款广泛使用的版本控制工具&#xff0c;它能够帮助开发者在开发过程中高效地管理代码的版本。而 Gitee&#xff08;码云&#xff09;是国内知名的 Git 托管平台&#xff0c;它提供了强大的代码托管、团队协作和项目管理功能。如果你是 Git 和 Gitee 的新手&#x…

挖掘机检测数据集,准确识别率91.0%,4327张原始图片,支持YOLO,COCO JSON,PASICAL VOC XML等多种格式标注

挖掘机检测数据集&#xff0c;准确识别率91.0%&#xff0c;4327张图片&#xff0c;支持YOLO&#xff0c;COCO JSON&#xff0c;PASICAL VOC XML等多种格式标注 数据集详情 数据集分割 训练组70&#xff05; 3022图片 有效集20&#xff05; 870图片 测试集10&…

CV 图像处理基础笔记大全(超全版哦~)!!!

一、图像的数字化表示 像素 数字图像由众多像素组成&#xff0c;是图像的基本构成单位。在灰度图像中&#xff0c;一个像素用一个数值表示其亮度&#xff0c;通常 8 位存储&#xff0c;取值范围 0 - 255&#xff0c;0 为纯黑&#xff0c;255 为纯白。例如&#xff0c;一幅简单的…

QT 使用QTableView读取数据库数据,表格分页,跳转,导出,过滤功能

文章目录 效果图概述功能点代码分析导航栏表格更新视图表格导出表格过滤 总结 效果图 概述 本案例用于对数据库中的数据进行显示等其他操作。数据库的映射&#xff0c;插入等功能看此博客框架&#xff1a;数据模型使用QSqlTableModel&#xff0c;视图使用QTableView&#xff0…

UI自动化测试:异常截图和page_source

自动化测试过程中&#xff0c;是否遇到过脚本执行中途出错却不知道原因的情况&#xff1f;测试人员面临的不仅是问题的复现&#xff0c;还有对错误的快速定位和分析。而异常截图与页面源码&#xff08;Page Source&#xff09;的结合&#xff0c;正是解决这一难题的利器。 在实…

Spark常见面试题-部分待更新

1. 简述hadoop 和 spark 的不同点&#xff08;为什么spark更快&#xff09; Hadoop是一个分布式管理、存储、计算的生态系统&#xff0c;包括HDFS&#xff08;分布式文件系统&#xff09;、MapReduce&#xff08;计算引擎&#xff09;和YARN&#xff08;资源调度器&#xff09;…

HackMyVM-Klim靶机的测试报告

目录 一、测试环境 1、系统环境 2、使用工具/软件 二、测试目的 三、操作过程 1、信息搜集 2、Getshell 3、提权 CVE-2008-0166 四、结论 一、测试环境 1、系统环境 渗透机&#xff1a;kali2021.1(192.168.159.127) 靶 机&#xff1a;debian(192.168.159.27) 注意事…

数据结构题目 课时6

题目 1、设一棵树的度是 4&#xff0c;其中度为 0, 1, 2, 3, 4 的结点个数分别是 8, 4, 2, 1 和&#xff08; &#xff09;。 A. 4 B. 3 C. 2 D. 1 2、设一棵 m 叉树中有 N₁个度数为 1 的结点&#xff0c;N₂个度数为 2 的结点&#xff0c;……&#xff0c;Nₘ个度…

Linux下源码编译安装Nginx1.24及服务脚本实战

1、下载Nginx [rootlocalhost ~]# wget -c https://nginx.org/download/nginx-1.24.0.tar.gz2、解压 [rootlocalhost ~]# tar xf nginx-1.24.0.tar.gz -C /usr/local/src/3、安装依赖 [rootlocalhost ~]# yum install gcc gcc-c make pcre-devel openssl-devel -y4、 准备 N…

Web前端------表单标签

一.表单标签介绍 1.认识表单 表单---类似于日常生活中的申请单 都是去填写一些信息去申请某个功能&#xff0c;例如&#xff1a;账号密码昵称&#xff0c;登陆网站 2.常见标签 常见的标签 <form></form> 表单标签&#xff0c;所有表单信息都包含在这个标签内…

LLM - 大模型 ScallingLaws 的迁移学习与混合训练(PLM) 教程(3)

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/145212097 免责声明&#xff1a;本文来源于个人知识与公开资料&#xff0c;仅用于学术交流&#xff0c;欢迎讨论&#xff0c;不支持转载。 Scalin…

Unity2017 控制.abc格式的三维动画播放

首先需要导入插件Alembic&#xff0c;否则导入abc动画&#xff0c;Unity是不会识别的。 Unity2017版本及以下直接从我这儿下载&#xff1a;https://download.csdn.net/download/qq_41603955/90272382 高版本Unity&#xff0c;请移步AssetStore商店搜找。 导入abc之后&#x…

【视觉惯性SLAM:十七、ORB-SLAM3 中的跟踪流程】

17.1 跟踪流程流程图 ORB-SLAM3 的跟踪模块是整个系统的重要组成部分&#xff0c;负责实时确定相机在三维空间中的姿态位置&#xff0c;并保持关键帧之间的连续性。其基本目标是将输入的视频流与已有地图数据进行对齐&#xff0c;完成位姿估计和地图更新。 流程图概述 一个…

开发神器之cursor

文章目录 cursor简介主要特点 下载cursor页面的简单介绍切换大模型指定ai学习的文件指定特定的代码喂给ai创建项目框架文件 cursor简介 Cursor 是一款专为开发者设计的智能代码编辑器&#xff0c;集成了先进的 AI 技术&#xff0c;旨在提升编程效率。以下是其主要特点和功能&a…

CSRF攻击XSS攻击

概述 ​在 HTML 中&#xff0c;<a>, <form>, <img>, <script>, <iframe>, <link> 等标签以及 Ajax 都可以指向一个资源地址&#xff0c;而所谓的跨域请求就是指&#xff1a;当前发起请求的域与该请求指向的资源所在的域不一样。这里的域指…

cuda + cudnn安装

1.安装CUDA Toolkit 在设备管理器&#xff08;此电脑–右键–属性&#xff09;的显示适配器中可以查看自己的显卡型号&#xff0c;去下载对应的CUDA Toolkit 。或者输入以下命令查看Driver Version &#xff0c;cuda Version&#xff1a;12.2代表12.2版本以下兼容可以进行安装 …