基础介绍:
想象这样一个场景,原项目中接口返回的数据是XML格式的数据,但现在来了一个新客户,它期望接口返回的数据类型为json格式的。
想要实现要么就是改原有接口,但这样就违反了开闭原则,容易出现未知bug,影响到老客户的正常使用。
而如果写一个适配器类也就是转换类(第三方类),将原本返回的XML格式数据转换成json格式数据,而具体数据是怎么来的则直接用原有接口方法就可以。
新客户只需要调用适配器类就可以了,而老客户这边也不会进行任何修改处理。
如果再有新的客户要求其他类型的返回,只需要在适配器类中增加相应的转换处理就可以了。
再思考一个问题,现实生活中空调插头一般都是三头的,但如果家里只有两孔插座,那必然是插不进去的。
以前老的办法那就是把三头插座掰掉一个,另外两个也掰直,这样做存在很大的安全隐患,而且有时并不能工作。
而如果提供一个拥有三孔插座和两头插头的转换器的话,那空调可以先插在这个转换器上,然后这个转换器再插在插座上就可以了。
本质并没有变,只是将二孔插座包装了一下,向外界提供了一个三孔插座的外观以供客户使用。
适配的本质就是转换,将不满足使用条件的东西通过第三方类进行加工处理成可使用的东西。
适配器模式(Apapter Pattern)是一种结构型设计模式,将一个类的接口转换成客户希望的另一个接口。适配器模式使得原本由于接口兼容而不能一起工作的那些类可以一起工作。
适配器模式用来解决现有对象与客户端期待接口不一致的问题。
- 目标角色(Target):描述了其他类与客户端代码合作时必须遵循的协议。
- 客户角色(Client):与符合Target接口的对象协同。
- 被适配(服务类,功能类)(Adaptee):定义一个已经存在并已经使用的接口,这个接口需要适配。 客户端与其接口不兼容, 因此无法直接调用其功能。
- 适配器(Adapter) :适配器模式的核心。适配器接受客户端通过适配器接口发起的调用,同时根据其内在逻辑调用对应服务类。客户端代码只需通过接口与适配器交互即可, 无需与具体的服务类耦合。
优缺点:
- 单一职责原则:可以将接口或数据转换代码从主要业务逻辑中分离。
- 开闭原则: 客户端接口只需适配器进行交互, 能在不修改现有代码的情况下在程序中添加新类型的适配器。
- 通过适配器模式,可以使两个不兼容的接口协同工作,避免了修改现有代码的需要。
- 提高了代码的复用性和灵活性,因为适配器可以重复使用,并且可以在不同的场景中使用。
- 降低了系统的耦合度,适配器模式允许系统中的各个组件相互独立地演化。
- 代码整体复杂度增加 :因为需要新增一系列接口和类。 有时直接更改服务类使其与其他代码兼容会更简单。
应用场景:
系统需要复用现有类,但是接口又与复用环境要求不一致的情况。
- 旧系统与新系统的兼容:可以使新系统能够无缝地与老旧系统进行通信。
- 第三方组件的集成:适配器可以将第三方组件的接口转换为符合我们系统需求的接口形式,从而能够顺利地集成到我们的系统中。
- 多个类库之间的互操作:适配器模式可以起到桥梁的作用。
创建方式:
适配器模式有两种实现结构,对象适配器和类适配器。
试想一下,目前有一个三头插头的空调,需要一个三孔插座,但目前只有一个两孔插座。
编写一个适配器来包装一下这个两孔插座,让用户可以使用这个空调。
-
类适配器
1 ///
2 /// 两孔插座---被适配者 3 /// 4 public class TwoHoleSocket 5 { 6 public void SpecificRequest() 7 { 8 Console.WriteLine("两孔插座"); 9 } 10 } 11 12 /// 13 /// 三孔插座---目标角色 14 /// 15 public interface IThreeHoleSocket 16 { 17 void Request(); 18 } 19 20 /// 21 /// 适配器类提供了三孔插座的外观,但其本质是两孔插座 22 /// 23 public class PowerAdapter : TwoHoleSocket, IThreeHoleSocket 24 { 25 public void Request() 26 { 27 Console.WriteLine("提供三孔插座的外观"); 28 //执行两孔插座的功能 29 this.SpecificRequest(); 30 } 31 } 32 33 /// 34 /// 客户端 35 /// 36 class Client 37 { 38 static void Main(string[] args) 39 { 40 //客户端可以通过适配器来使用这个两孔插座了(因为外观已经是三孔的了) 41 IThreeHoleSocket threeHoleSocket = new PowerAdapter(); 42 threeHoleSocket.Request(); 43 Console.ReadKey(); 44 } 45 } TwoHoleSocket类代表原有的两孔插座,IThreeHoleSocket接口来规范三孔插座的外观。
PowerAdapter类代表适配器,将两孔插座赋予三孔插座的外观。
这样用户就可以使用这个适配器来使用这个三头插头的空调了。
从实例中可以看出,类适配器只要是用继承来实现的,但如果有很多个类进行适配,这个方式就不支持了。
-
对象适配器
1 ///
2 /// 两孔插座---被适配者 3 /// 4 public class TwoHoleSocket 5 { 6 public void SpecificRequest() 7 { 8 Console.WriteLine("两孔插座"); 9 } 10 } 11 12 /// 13 /// 三孔插座---目标角色 14 /// 15 public class ThreeHoleSocket 16 { 17 // 客户端需要的方法 18 public virtual void Request() 19 { 20 //具体实现 21 } 22 } 23 24 /// 25 /// 适配器类提供了三孔插座的外观,但其本质是两孔插座 26 /// 27 public class PowerAdapter : ThreeHoleSocket 28 { 29 //引用两孔插座的实例,从而将客户端与TwoHoleSocket联系起来 30 public TwoHoleSocket twoHoleSocket = new TwoHoleSocket(); 31 public override void Request() 32 { 33 Console.WriteLine("提供三孔插座的外观"); 34 this.Request(); 35 //执行两孔插座的功能 36 twoHoleSocket.SpecificRequest(); 37 } 38 } 39 40 /// 41 /// 客户端 42 /// 43 class Client 44 { 45 static void Main(string[] args) 46 { 47 //客户端可以通过适配器来使用这个两孔插座了(因为外观已经是三孔的了) 48 ThreeHoleSocket threeHoleSocket = new PowerAdapter(); 49 threeHoleSocket.Request(); 50 Console.ReadKey(); 51 } 52 } 从实例中可以看出,对象适配器其实就是在适配器类中创建了一个被适配者的实例,从而将两者联系在一起。
这种方式采用 “对象组合”的方式,更符合松耦合。
总结:
总而言之,适配器就是一个第三方类,将不合时宜的东西转换成符合心意的工具类。
本质就是转换。