【愚公系列】2023年10月 二十三种设计模式(六)-适配器模式(Adapter Pattern)
🏆 作者简介,愚公搬代码
🏆《头衔》:华为云特约编辑,华为云云享专家,华为开发者专家,华为产品云测专家,CSDN博客专家,阿里云专家博主,腾讯云优秀博主,掘金优秀博主,51CTO博客专家等。
🏆《近期荣誉》:2022年CSDN博客之星TOP2,2022年华为云十佳博主等。
🏆《博客内容》:.NET、Java、Python、Go、Node、前端、IOS、Android、鸿蒙、Linux、物联网、网络安全、大数据、人工智能、U3D游戏、小程序等相关领域知识。
🏆🎉欢迎 👍点赞✍评论⭐收藏
🚀前言
设计模式(Design Pattern)是软件开发领域的宝贵经验,是多人反复借鉴和广泛应用的代码设计指导。它们是一系列经过分类和归纳的代码组织方法,旨在实现可重用性、可维护性和可理解性。使用设计模式,我们能够编写高质量的代码,使其更易于他人理解,并提供了代码可靠性的保证。
毫无疑问,设计模式对个人、团队和整个系统都带来了显著的益处。它们将代码开发提升到工程化水平,为软件工程构建提供了坚实的基础,就如同大厦的一块块精巧的砖石一样。在项目中明智地应用设计模式可以完美地解决各种复杂问题。每种设计模式都有相应的原理和最佳实践,它们描述了我们日常开发中不断遇到的问题,以及这些问题的核心解决方法。正是因为这种实用性和通用性,设计模式才能在软件开发中广泛地得以应用。设计模式是构建稳健、可扩展和可维护软件的关键工具,为开发者们提供了解决问题的智慧和指导。
🚀一、适配器模式(Adapter Pattern)
适配器模式是一种结构型设计模式,它允许将一个类的接口转换成客户端所期望的另一种接口。这种模式使得原本由于接口不匹配而无法一起工作的两个类能够协同工作。
适配器模式通常分为四种类型:类适配器模式、对象适配器模式、单接口适配器模式(也称为缺省适配器模式)和双向适配器模式。其中,类适配器模式和对象适配器模式是最常见且最广泛使用的。
类适配器模式:在类适配器模式中,适配器类继承了目标类(待适配的类),并实现了客户端所期望的接口。这种方式使用多重继承来适配接口,因此只适用于支持多继承的编程语言。
对象适配器模式:在对象适配器模式中,适配器类持有一个待适配的对象实例,并实现了客户端所期望的接口。适配器类将客户端的请求委派给内部的待适配对象,从而实现接口的适配。
值得注意的是,后两种模式(单接口适配器模式和双向适配器模式)在实际开发中较少使用,因为它们的实现相对复杂,并且通常可以通过类适配器模式或对象适配器模式来满足需求。
适配器模式在实际应用中常用于以下情况:
- 将旧的接口适配成新的接口,以兼容不同版本或不同系统的组件。
- 将第三方库或组件与自己的代码进行集成,但它们的接口不匹配时。
- 在系统演化过程中,用于逐步替换或升级旧组件,以确保新组件与原有代码兼容。
适配器模式是一种有用的工具,可以帮助我们有效地解决接口不匹配的问题,提高代码的可维护性和可扩展性。根据具体的情况选择合适的适配器类型,可以让我们更灵活地应对不同的需求。
🚀二、使用步骤
🔎1.角色
🦋1.1 抽象目标(Target)
适配器模式(Adapter Pattern)中的抽象目标(Target)是一个关键概念,它在模式中扮演着重要的角色。以下是抽象目标在适配器模式中的概念和作用:
概念:
抽象目标(Target)是适配器模式中的一个接口或抽象类,它代表了客户端代码所期望的接口或功能。这个接口定义了客户端代码需要与之交互的方法和行为。
作用:
定义客户端的期望接口:抽象目标定义了客户端所期望的接口,这意味着客户端代码将使用这个抽象目标来调用特定的方法或执行特定的操作。
解耦客户端和适配器的具体实现:通过使用抽象目标,客户端代码与适配器的具体实现分离开来。客户端不需要知道适配器是如何工作的,它只需要与抽象目标交互。
支持多态性:抽象目标使得不同的适配器可以实现相同的接口,从而支持多态性。这意味着客户端代码可以与不同的适配器交互,而无需关心适配器的具体类型。
简化客户端代码:通过使用抽象目标,客户端代码变得更加简洁和可读。客户端只需关注所需功能的调用,而不需要关心适配器内部的复杂逻辑。
抽象目标在适配器模式中起到了定义接口和提供一个标准的交互方式的作用。它有助于实现客户端与适配器之间的松耦合,并支持代码的可扩展性和可维护性。适配器模式的关键思想是通过抽象目标来桥接客户端与待适配对象之间的差异,使它们能够协同工作,实现了接口的适配。
🦋1.2 适配器(Adapter)
适配器模式(Adapter Pattern)中的适配器(Adapter)是该模式的核心组件,它扮演着重要的角色。以下是适配器在适配器模式中的概念和作用:
概念:
适配器是一个中间层或类,它的主要任务是将一个类的接口转换成另一个类的接口,以满足客户端的需求。适配器充当了连接客户端和待适配对象之间的桥梁,使它们能够协同工作。
作用:
接口转换:适配器的主要作用是将待适配对象的接口转换成客户端所期望的接口。这样,客户端可以使用适配器的接口来调用待适配对象的功能。
解决接口不匹配问题:适配器解决了由于接口不匹配而导致客户端无法直接与待适配对象交互的问题。它将待适配对象包装在内部,并提供与客户端期望的接口一致的方法。
适应不同接口的类:适配器可以适应不同接口的类,使它们能够在同一个客户端中一起工作。这样,无需修改现有类的代码,就可以实现新的功能或集成第三方组件。
保持客户端代码稳定:适配器模式可以使客户端代码保持稳定,因为客户端只与适配器的接口交互,而不需要了解待适配对象的内部结构和接口。
支持复用:适配器模式支持将现有的类或组件集成到新的系统中,以提高代码的复用性和可维护性。
适配器在适配器模式中充当了一个接口转换器的角色,它的主要任务是解决接口不匹配的问题,使客户端能够与待适配对象协同工作。适配器模式是一种非常有用的设计模式,特别适用于集成或使用现有代码库、组件或第三方库时,以确保不同接口之间的协同工作。适配器的实现方式可以是类适配器模式或对象适配器模式,具体取决于设计需求和编程语言的支持。
🦋1.3 适配者(Adaptee)
在适配器模式(Adapter Pattern)中,适配者(Adaptee)是指需要被适配的现有类或对象,它具有一个或多个不符合客户端期望接口的方法或功能。适配者是适配器模式的关键组成部分,以下是适配者在该模式中的概念和作用:
概念:
适配者是指那些已经存在的类或对象,它们的接口与客户端所期望的接口不匹配。适配者具有自己的方法和功能,但这些方法与客户端代码的需求不一致。
作用:
提供功能:适配者包含了客户端需要的功能或业务逻辑。虽然它的接口不匹配客户端的期望,但它仍然具有有用的功能。
不改变已有代码:适配者允许在不修改现有代码的情况下将其集成到适配器模式中。这对于已有的稳定代码库或第三方组件非常有用。
支持适配器的工作:适配者是适配器的工作目标。适配器的任务是将适配者的接口转换成客户端所期望的接口,以便客户端可以使用适配者的功能。
解决接口不匹配问题:适配者的主要作用是解决由于接口不匹配而导致的问题。适配器模式的目标是让客户端代码能够与适配者一起工作,而不需要修改适配者的接口。
适配者是适配器模式中的现有类或对象,它包含了客户端需要的功能,但其接口与客户端期望的接口不匹配。适配器模式的适配器(Adapter)的任务是将适配者的接口转换成客户端所期望的接口,以便客户端可以使用适配者的功能,同时保持适配者不受影响。适配者允许在现有代码基础上实现接口适配,提高代码的复用性和可维护性。
🔎2.示例
命名空间AdapterPattern包含ClassBased和ObjectBased子命名空间,分别表示基于类的适配器模式和基于对象的适配器模式。类的适配器中包含家用电器类、电压类、目标动作接口和手机适配器类。对象的适配器中包含适配者、适配器、目标接口和目标基类。本案例尝试使用手机适配器将家用电器的电压从220V适配至3V。
namespace AdapterPattern
🦋2.1 类的适配器模式
namespace AdapterPattern.ClassBased
public class Voltage {
public uint Value { get; set; }
}
电压Voltage类,包含一个无符号int类型的电压值。
public class Appliance {
public Voltage GetVoltage() {
return new Voltage { Value = 220 };
}
}
家用电器Appliance类,包含一个获取电压的GetVoltage方法。
public interface ITarget {
Voltage GetMobileVoltage();
}
目标接口ITarget,包含一个获取手机电压的GetMobileVoltage方法。这是我们要适配的目标动作。
public class MobileAdapter : Appliance, ITarget {
public Voltage GetMobileVoltage() {
var voltage = GetVoltage();
Console.WriteLine($"Appliance voltage is {voltage.Value}V!");
voltage.Value = 3;
Console.WriteLine($"After adapted,it becomes {voltage.Value}V!");
return voltage;
}
}
手机适配器MobileAdapter类,继承自Applicance家用电器并实现ITarget接口。
🦋2.2 对象的适配器模式
namespace AdapterPattern.ObjectBased
public class Adaptee {
public void OriginalMethod() {
Console.WriteLine("Original Method is being called!");
}
}
适配者Adaptee类,这是将要被我们适配的类。
public interface ITarget {
void TargetMethod();
}
目标接口ITarget,定义我们的目标动作。
public class Target : ITarget {
public virtual void TargetMethod() {
Console.WriteLine("Target Method is being called!");
}
}
目标Target类,实现目标接口以实现动作。
public class Adapter : Target {
private Adaptee _adaptee = new Adaptee();
public override void TargetMethod() {
_adaptee.OriginalMethod();
}
}
适配器Adapter类,继承自Target类。内部维持对适配者的引用并实现一个目标动作。
public class Program {
private static ClassBased.ITarget _targetClass = null;
private static ObjectBased.ITarget _targetObject = null;
public static void Main(string[] args) {
//Class Pattern
_targetClass = new ClassBased.MobileAdapter();
var voltage = _targetClass.GetMobileVoltage();
Console.WriteLine("-----------------------------");
//Object Pattern
_targetObject = new ObjectBased.Adapter();
_targetObject.TargetMethod();
Console.ReadKey();
}
}
以上是调用方的代码,分别演示了类的适配器模式和对象的适配器模式的用法。以下是这2个案例的输出结果:
Appliance voltage is 220V!
After adapted,it becomes 3V!
-----------------------------
Original Method is being called!
🚀总结
🔎1.优点
适配器模式(Adapter Pattern)有许多优点,这些优点使其成为一种常用的设计模式,特别是在集成已有代码或组件、处理接口不匹配的情况下。以下是适配器模式的一些主要优点:
解耦性增强:适配器模式可以帮助解耦客户端代码和待适配对象之间的关系。客户端不需要了解待适配对象的内部实现细节,只需与适配器交互。
重用现有代码:适配器允许将现有的类或组件集成到新的系统中,无需修改其原始代码。这有助于最大限度地重用已有的稳定代码。
支持多态性:适配器模式支持多态性,不同的适配器可以实现相同的接口,从而使客户端可以与不同类型的适配器交互,实现灵活的代码设计。
增加可维护性:通过使用适配器,可以更容易地维护和扩展系统,因为适配器将客户端与待适配对象的关系封装在一起,简化了修改和扩展的过程。
提高代码可读性:适配器模式使客户端代码更加清晰和可读,因为客户端只需与适配器的接口交互,无需关心待适配对象的复杂性。
支持适配不同接口:适配器模式可以用于适配不同接口的对象,使它们能够在同一个系统中协同工作,从而提供了更大的灵活性。
平滑过渡:适配器模式可以用于实现平滑过渡,当需要逐步替换一个旧的系统或组件时,可以先引入适配器,然后逐步迁移到新的实现。
适配器模式的优点包括解耦性增强、代码重用、多态性支持、可维护性提高、代码可读性提高等。它是一种非常有用的设计模式,特别适用于集成已有代码、处理接口不匹配或实现系统的平滑过渡。通过适配器模式,可以改善代码的结构和可维护性,同时保持系统的灵活性。
🔎2.缺点
尽管适配器模式(Adapter Pattern)在许多情况下非常有用,但它也有一些缺点和限制,需要考虑:
增加复杂性:引入适配器模式可能会增加代码的复杂性,特别是在系统中存在多个适配器时。每个适配器都需要编写和维护,这可能导致代码变得更加复杂。
潜在性能开销:适配器模式可能引入一些性能开销,因为它需要在客户端和待适配对象之间添加一个额外的层。在某些高性能要求的场景中,这可能会成为一个问题。
不适用于所有情况:适配器模式并不适用于所有情况。如果可以修改待适配对象的代码来使其符合客户端的接口,那么适配器模式可能不是最佳选择。适配器应该是一种在无法修改待适配对象的情况下的备选方案。
可能引入歧义:在某些情况下,使用适配器模式可能会引入歧义,因为客户端可能会误解适配器的功能,认为它提供了更多的功能而不仅仅是接口转换。
需要额外开发工作:实现适配器模式需要额外的开发工作,包括编写适配器类和测试。这可能会增加开发时间和成本。
不解决根本问题:适配器模式通常是一种应急措施,用于解决接口不匹配的问题。它并不解决根本问题,即待适配对象的接口设计不合理。更好的做法是在设计阶段考虑接口的一致性。
适配器模式虽然在某些情况下非常有用,但在应用时需要权衡其优点和缺点。在选择是否使用适配器模式时,应仔细考虑系统需求、性能要求和代码复杂性,确保它是解决问题的合适选择。如果可能的话,应该优先考虑设计阶段的接口一致性,以减少适配器的需求。
🔎3.使用场景
适配器模式(Adapter Pattern)在以下情况下是非常有用的,它可以用来解决接口不匹配或集成现有代码的问题:
集成第三方库:当你需要集成一个第三方库或组件到你的应用中,但其接口与你的应用不兼容时,适配器模式可以帮助你将这些库无缝地集成到你的代码中。
使用旧系统:当你需要在新系统中使用旧系统或旧组件的功能,但它们的接口已经过时或不符合新系统的设计时,适配器模式可以用来在新系统中包装和使用旧系统。
统一接口:当你希望统一多个类或对象的接口以便客户端可以一致地使用它们时,适配器模式可以帮助你创建适配器,将它们的接口转换成统一的接口。
使用不同的数据源:当你需要从不同的数据源获取数据,但这些数据源具有不同的数据格式或接口时,适配器模式可以用来标准化数据的访问方式。
改善系统的可维护性:当你需要改善系统的可维护性,并且希望通过解耦客户端和待适配对象来实现这一目标时,适配器模式可以帮助你达到这个目标。
接口升级:当一个接口需要升级或扩展,但你希望保持对旧接口的兼容性时,可以创建适配器来适配新接口并保持对旧接口的支持。
多态性支持:适配器模式可以用来支持多态性,允许客户端代码以一致的方式处理不同类型的适配器对象。
适配器模式的主要使用场景涵盖了解决接口不匹配、集成第三方库、统一接口、改善可维护性等情况。它是一种强大的设计模式,可以帮助你在不修改现有代码
🚀感谢:给读者的一封信
亲爱的读者,
我在这篇文章中投入了大量的心血和时间,希望为您提供有价值的内容。这篇文章包含了深入的研究和个人经验,我相信这些信息对您非常有帮助。
如果您觉得这篇文章对您有所帮助,我诚恳地请求您考虑赞赏1元钱的支持。这个金额不会对您的财务状况造成负担,但它会对我继续创作高质量的内容产生积极的影响。
我之所以写这篇文章,是因为我热爱分享有用的知识和见解。您的支持将帮助我继续这个使命,也鼓励我花更多的时间和精力创作更多有价值的内容。
如果您愿意支持我的创作,请扫描下面二维码,您的支持将不胜感激。同时,如果您有任何反馈或建议,也欢迎与我分享。
再次感谢您的阅读和支持!
最诚挚的问候, “愚公搬代码”
- 点赞
- 收藏
- 关注作者
评论(0)