1:主题拆解
①基本介绍
②IPhone手机充电场景模拟
③类适配器与对象适配器的区别
④适配器模式的优缺点
⑤适用场景
⑥C#.NET中的使用场景
2:基本介绍
Adapter适配器模式,将一个类的接口转换成客户希望的另外一个接口。使原本由于接口不兼容而不能一起工作的那些类可以一起工作了。
适配器模式有“类适配器”和“对象适配器”两种不同的形式。
3:IPhone手机充电场景模拟
以下以苹果手机充电方式来模拟适配器模式的应用
1:基础版
国行IPhone8与IPhoneX充电
①定义充电接口
public interface IAdapterHelper{void Charging<T>();}
②IPhone8与IPhoneX继承并且实现充电功能
public class IPhone8Helper : IAdapterHelper{ public void Charging<T>(){Console.WriteLine("This is {0} 两脚插座", this.GetType().Name);}}public class IPhoneXHelper : IAdapterHelper{public void Charging<T>(){Console.WriteLine("This is {0} 两脚插座", this.GetType().Name);}}
③上端调用充电方法
IAdapterHelper helper8 = new IPhone8Helper();
helper8.Charging<Program>();
IAdapterHelper helperx = new IPhoneXHelper();
helperx.Charging<Program>();
分析:此处实现了最基础版本的充电场景,如果此时来了一个港币的IPhonex该如何充电?
2:升级版?
引入港版IPhonex
public class IPhoneX4HKHelper{public void ChargingHK<T>(){Console.WriteLine("This is {0} 三脚插座", this.GetType().Name);}}
分析:此处由于接口不通用,无法直接进行充电,此时就需要一个转接器,即引入适配器的概念。
3:升级版-类适配器模式
①添加适配器类IPhoneX4HKHelperClass
public class IPhoneX4HKHelperClass : IPhoneX4HKHelper, IAdapterHelper{public void Charging<T>(){base.ChargingHK<T>();}}
②上端调用港版IPhonex充电
IAdapterHelper helperxhk = new IPhoneX4HKHelperClass();
helperxhk.Charging<Program>();
分析:适配器类继承原港版充电实现类,并且实现国行通用充电的方法。此为适配器模式中的类适配器模式。
4:升级版-对象适配器模式
①添加适配器类IPhoneX4HKHelperClass
public class IPhoneX4HKHelperObject : IAdapterHelper{private IPhoneX4HKHelper _RedisHelper = new IPhoneX4HKHelper();public void Charging<T>(){_RedisHelper.ChargingHK<T>();}}
②上端调用港版IPhonex充电
IAdapterHelper helperxhkobj = new IPhoneX4HKHelperObject();
helperxhkobj.Charging<Program>();
分析:适配器类继承通用接口,并且实例化港版的对象,通过对象的方法再进行转换已实现充电接口。此为适配器模式中的对象适配器模式。
在不修改接口,也不修改实现类的情况下,通过新增一个适配器的方式让上端的使用更加轻松。
4:类适配器与对象适配器的区别
1:类适配器
采用的是继承的方式实现的,与父类强耦合在一起,不管是好的坏的一并都继承,具有侵入性,如果子类取名与父类冲突了,还会影响理氏替换。
2:对象适配器
采用的是组合的方式实现,其类的行为是自身控制的。会更加灵活。并且如果在对象适配器中结合依赖注入的方式更加增加程序的可扩展性
因此:架构设计中,组合优于继承
5:适配器模式的优缺点
1:优点
①类适配器以及对象适配器的共同优点如下:
解耦:将Target与Adaptee解耦,引入适配器来重用现有的适配者类,无须修改原有结构
提高复用性:将具体的业务实现过程封装在适配者类中,对于客户端而言是透明的,而且提高了适配者类的复用性,同一个适配者类可以在多个不同的系统复用
扩展性好:可以很方便地更换适配器,也可以在不修改代码的基础上增加了新的适配器类,完全符合开闭原则,扩展灵活
②类适配器的独有优点如下:
由于适配器类是适配者的子类,因此在适配器类中置换一些适配者的方法,使得适配器的灵活性更强。
③对象适配器的独有优点如下:
一个对象适配器可以把多个不同的适配者适配到同一个Target
可以适配一个适配者的子类,由于适配器与适配者之间是关联关系,根据LSP(里氏代换原则),适配者的子类也可以通过该适配器进行适配
2:缺点
①类适配器缺点:
对于Java,C#等不支持多重继承的语言,一次最多只能适配一个适配者类
适配者不能是“不能继承的类”,比如Java的final类,C#的sealed类
在Java,C#等Target只能是接口不能是类
②对象适配器缺点:
置换麻烦:相比起类适配器,在适配器中置换适配者的某些方法比较麻烦,需要先创建一个适配者类的子类,在子类将适配者类的方法置换掉,再把适配者的子类作为真正的适配者类进行适配,实现较为复杂
6:适用场景
1:系统需要使用一些现有的类,而这些类的接口(如方法名)不符合系统的需求和标准,没法直接修改源码,甚至没有这些类的源代码。
2:基于现有的系统进行集成改造,或者现有的系统很强大,需要额外增加一些第三方的扩展时,而第三方的扩展与当前的接口并不吻合。
7:C#.NET中的使用场景
ADO.NET中的DataAdapter,即其中的DataSet集合,该集合没有任何规则,可以塞一堆的DataTable,也可以塞一堆的元素,又杂又乱。但是有个好处就是可以包容一切。
DataAdapter本质上就是为了适配不同的数据源,例如mysql,sqlserver,oracle。由于每种数据源都有不同的数据格式,程序为了避免为所有的数据源都分别写对应的实现。因此就借助DataAdapter适配器把数据库中查询的数据转到DataSet中,至于数据源是哪种,上端调用不用关心底层的数据源。