适配器模式介绍
适配器模式的作用就是把原本不兼容的接口,通过适配修改到统一的过程,使得用户方便使用。
在实际工作中, 有时候我们需要把各个业务线的各种类型服务做统一的包装,再对外提供接口进行使用。
适配器模式要解决的主要问题就是多种差异化类型的接口做统一输出。
适配器可担任两个对象间的封装器,它会接收对于一个对象的调用,并将其转换为另一个对象可识别的格式和接口。
适配器模式通过封装对象将复杂的转换过程隐藏于幕后。被封装的对象甚至察觉不到适配器的存在。
适配器模式结构
- 对象适配器
构成原则:适配器实现其中一个对象的接口,并对另一个对象进行封装。
1、客户端:包含当前程序业务逻辑的类。
2、客户端接口:描述了其他类与客户端代码合作时必须遵循的协议。
3、服务:其中的有些功能类或方法,客户端无法直接调用其功能,无法进行使用。
4、适配器:可以同时与客户端和服务交互的类,它在实现客户端接口的同时封装了服务对象。适配器接受客户端通过适配器接口发起的调用,并将其转换为适用于被封装服务对象的调用。
客户端代码只需通过接口与适配器交互即可,无需与具体的适配器耦合。这在服务类接口被更改或替换时很有用,你无需修改客户端代码就可以创建新的适配器类。
- 类适配器
通过继承机制,适配器同时继承两个对象的接口。此种方式只在支持多重继承的编程语言中实现,例如C++
类适配器不需要封装任何对象,因为它同时继承了客户端和服务的行为。适配功能在重写的方法中完成,最好生成的适配器可替代已有的客户端类进行使用。
适配器模式优缺点
优点:
- 使得代码干净整洁,易于维护,减少大量重复的判断和使用,让代码更加易于维护和扩展。
- 单一职责原则,可以将接口或数据转换代码从程序主要业务逻辑中分离。
- 开闭原则,客户端代码通过客户端接口与适配器进行交互,你就能在不修改现有客户端代码的情况下在程序中添加新类型的适配器。
缺点:
- 代码复杂度增加,需要增加很多接口和类
Demo
/// <summary> /// 接口类,客户端类 /// </summary> public interface ITarget { string GetRequest(); }
/// <summary> /// 被适配者 例如遗留老代码,开源模块等 /// </summary> public class Adaptee { public string GetSpecificRequest() { return "特殊的请求 遗留的老代码"; } }
/// <summary> /// 适配器 /// </summary> public class Adapter:ITarget { private readonly Adaptee _adaptee; public Adapter(Adaptee adaptee) { this._adaptee = adaptee; } /// <summary> /// 显示实现的接口类 /// 在这里可以调用遗留老代码的方法。 /// </summary> /// <returns></returns> public string GetRequest() { return "我正在调用:" + _adaptee.GetSpecificRequest(); } }
class Program { static void Main(string[] args) { Console.WriteLine("Start Test Adapter Mode"); //实例化老代码模块 Adaptee tempAdaptee = new Adaptee(); ITarget adapter = new Adapter(tempAdaptee); //通过实现的接口去调用老代码模块中的方法。 var showResult=adapter.GetRequest(); Console.WriteLine(showResult); Console.ReadKey(); } }
可以看到在上述代码中,我们通过适配器去直接调用的老代码中的方法。在我们平时的开发过程中,适配器使用的场景还是很多的,比如系统对开源组件的支持,多设备的支持等。对于设计模式而言,要学会注意它的使用场景,也只有在合适的场景下使用它,才能发挥它最大的效果。
适配器可以通过以不同抽象或接口实例为参数的构造函数来识别。当适配器的任何方法被调用时,它会将参数转换为合适的格式,然后将调用定向到其封装对象中的一个或多个方法。