设计模式-适配器模式(Adapter)
简介:
适配器模式在我看来是最无聊的一种模式,因为他根本不是一种新的创意模式,而是一种不得已而为之的模式。就算不学适配器模式,在具体应用场景中也会自然而然的想到这种解决方案。
张三在英国留学时买了个笔记本,使用的外接电源为欧式标准。现在回国了(中国电源标准不同意欧洲标准),要想让笔记本继续正常工作,有两种方案,1为重新改造笔记本,2为买个电源转换器,将欧式电源转换为中式电源。
上面中的1,重新改造笔记本,相当于我们软件工程中的代码重构,难度大,风险高。
2即为本文中所描述的适配器模式,只需要稍微修改外部调用接口,内部实现逻辑不用改变。
适配器模式的定义:
将一个类的接口转换为客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
转换匹配,复用功能
适配器模式的组成:
1.Target 定义客户端需要的接口。即上文的中式电源接口
2.Adaptee,已经存在的接口,通常已经能够满足客户的需求,但是接口跟客户端要求的不大一致。即上文的英式电源接口
3.Adapter:适配器,将Adaptee转换为Target,即适配器模式的核心。
继承Target类或者实现Target接口
需要传入Adaptee对象参数,对外展现为Target的接口方法,内部实现实为Adaptee接口方法。
代码如下:
电脑原始的英式电源(以及其接口类,欧式电源):
/// <summary> /// 欧式电源供电API /// </summary> public interface EurPowerSupplyApi { /// <summary> /// 充电 /// </summary> /// <returns></returns> void Charge(); /// <summary> /// 供电 /// </summary> /// <returns></returns> void Supply(); } /// <summary> /// 英式电源供电,对应适配器模式中的Adaptee /// </summary> public class UKPowerSupply : EurPowerSupplyApi { public Power MyPower { get { return _myPower; } set { _myPower = value; } } private Power _myPower; public void Charge() { Console.WriteLine("I am using UK PowerSupply."); } public void Supply() { Console.WriteLine("The UK PowerSupply is supplying my PC"); } }
原始调用代码为:
/// <summary> /// 原始英式电源供电测试类 /// </summary> public class AddpterTest { public static void Main(string[] args) { EurPowerSupplyApi powerSupply = new UKPowerSupply(); //英式电源充电中 powerSupply.Charge(); //英式电源供电中 powerSupply.Supply(); Console.ReadLine(); } }
中式电源接口(方法名、方法参数都不同于原来的欧式电源接口)
/// <summary> /// 中式电源供电API /// </summary> public interface ChinesePowerSupplyAPI { void ChongDian(Power aPower); void GongDian(Power aPower); }
适配器代码为:
/// <summary> /// 电源转换器,对应适配器模式中的Adapter,需要实现客户端将于调用的接口(ChinesePowerSupplyAPI)的方法 /// </summary> public class PowerSupplyAdapter : ChinesePowerSupplyAPI { /// <summary> /// 将要被适配、被转换的接口对象,对应适配器模式中的Adaptee /// </summary> private EurPowerSupplyApi adaptee; /// <summary> /// 构造函数,传入Adaptee /// </summary> /// <param name="aAdaptee"></param> public PowerSupplyAdapter(EurPowerSupplyApi aAdaptee) { this.adaptee = aAdaptee; } /// <summary> /// 实现Target的ChongDian方法 /// </summary> /// <param name="aPower"></param> public void ChongDian(Power aPower) { adaptee.Charge(); } /// <summary> /// 实现Target的GongDian方法 /// </summary> /// <param name="aPower"></param> public void GongDian(Power aPower) { adaptee.Supply(); } }
适配器测试代码为:
/// <summary> /// Apapter测试类 /// </summary> public class AddpterTest { public static void Main(string[] args) { //现有英国电源充电器 UKPowerSupply ukSupply = new UKPowerSupply(); ukSupply.MyPower = new Power(80); //电源适配器,传入英国电源,可以转换为中式电源 PowerSupplyAdapter adapter = new PowerSupplyAdapter(ukSupply); adapter.ChongDian(ukSupply.MyPower); adapter.GongDian(ukSupply.MyPower); Console.ReadLine(); } }
补充描述:
1.适配器模式的主要功能时进行转换匹配,目的是复用已有的功能,而不是来实现新的接口。主要负责将不兼容的接口转换客户端期望的样子即可。
2.Adaptee和Target一般为同类对象(如上文中欧式电源接口和中式电源接口),也可以为前后不同的两个版本接口。本身是没有关联的,内部方法签名可以相同,也可以不同(如本文方法名称和参数都不相同)。
3.双向适配器。
上面的例子是适配器的功能是把欧式电源转换为中式电源,同样的,也可以把中式电源转换为欧式电源,还可以把这两个接口放在同一个类中。