在实际的软件系统设计和开发中,为了完成某项工作需要购买一个第三方的库来加快开发。这带来一个问题,在应用程序中已经设计好的功能接口,与这个第三方提供的接口不一致。为了使得这些接口不兼容的类可以在一起工作,适配器模式提供了一种接口的适配机制。
适配器模式的设计思想在生活中经常会应用到,如我们在给手机充电的时候,不可能直接在220V电源上直接充电,而是用手机充电器转换成手机需要的电压才可以正常充电,否则就不可以完成充电,这个充电器就起到了适配的作用。
1、适配器模式简介
1.1>、定义
适配器模式是通过一个类的接口转换成客户希望的另外一个接口,使原本由于接口不兼容而不能一起工作的那些类可以一起工作。
适配器从结构上可以分为类适配器和对象适配器。其中类适配器使用继承关系来对类进行适配,而对象适配器是使用对象引用的方法来进行适配的。
C#实现类适配器时,Target只能是接口。实现对象适配器时,Target可以是抽象类也可以是接口。
1.2>、使用频率
中高
2、类适配器模式结构
2.1>、结构图
类适配器结构图
对象适配器结构图
2.2>、参与者
适配器模式参与者:
◊ Target:Client所使用的与特定领域相关的接口。
◊ Client:与符合Target接口的对象协调的类。
◊ Adaptee:需要适配的类接口。
◊ Adapter:适配器,负责Adaptee的接口与Target接口进行适配。
在适配器模式中,类Adapter实现适配器的功能,它在Client于Adaptee之间加入Adapter,这样Client把请求发给接口为Target的类Adapter,再由Adapter调用Adaptee,从而实现Client调用Adaptee。
3、适配器模式结构实现
3.1>、类适配器结构实现
ITarget.cs:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AdapterPattern.Structural.ClassAdapter { public interface ITarget { void Request(); } }
Adaptee.cs:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AdapterPattern.Structural.ClassAdapter { public class Adaptee { public void SpecificRequest() { Console.WriteLine("Called SpecificRequest()"); } } }
Adapter.cs:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AdapterPattern.Structural.ClassAdapter { public class Adapter : Adaptee, ITarget { public void Request() { this.SpecificRequest(); } } }
Client.cs:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AdapterPattern.Structural.ClassAdapter { public class Client { static void Main(string[] args) { ITarget t = new Adapter(); t.Request(); } } }
运行输出:
Called SpecificRequest() 请按任意键继续. . .
3.2>、对象适配器结构实现
Client需要调用Request方法,而Adaptee并没有该方法,为了使Client能够使用Adaptee类,需要提供一个类Adapter。这个类包含了一个Adaptee的实例,将Client与Adaptee衔接起来。
ITarget.cs:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AdapterPattern.Structural.ObjectAdapter { public interface ITarget { void Request(); } }
Target.cs:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AdapterPattern.Structural.ObjectAdapter { public class Target : ITarget { public virtual void Request() { Console.WriteLine("Called Target Request()"); } } }
Adaptee.cs:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AdapterPattern.Structural.ObjectAdapter { public class Adaptee { public void SpecificRequest() { Console.WriteLine("Called SpecificRequest()"); } } }
Adapter.cs:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AdapterPattern.Structural.ObjectAdapter { public class Adapter : Target { private Adaptee _adaptee = new Adaptee(); public override void Request() { _adaptee.SpecificRequest(); } } }
Client.cs:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AdapterPattern.Structural.ObjectAdapter { public class Client { static void Main(string[] args) { ITarget t = new Adapter(); t.Request(); } } }
4、适配器模式实践应用
以手机充电的电源适配器为例,用适配器模式的解决方案。
4.1>、类适配器结构实现
ITarget.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AdapterPattern.Practical.ClassAdapter { public interface ITarget { void GetPower(); } }
Power.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AdapterPattern.Practical.ClassAdapter { public class Power { public void GetPower220V() { Console.WriteLine("从电源中得到220V的电压"); } } }
Adapter.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AdapterPattern.Practical.ClassAdapter { public class Adapter : Power, ITarget { public void GetPower() { this.GetPower220V(); Console.WriteLine("得到手机的充电电压!"); } } }
Client.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AdapterPattern.Practical.ClassAdapter { public class Client { static void Main(string[] args) { Console.WriteLine("手机:"); ITarget t = new Adapter(); t.GetPower(); } } }
运行输出:
手机: 从电源中得到220V的电压 得到手机的充电电压! 请按任意键继续. . .
4.2>、对象适配器结构实现
ITarget.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AdapterPattern.Practical.ObjectAdapter { public interface ITarget { void GetPower(); } }
Power.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AdapterPattern.Practical.ObjectAdapter { public class Power { public void GetPower220V() { Console.WriteLine("从电源中得到220V的电压"); } } }
Adapter.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AdapterPattern.Practical.ObjectAdapter { public class Adapter : ITarget { public Power _power; public Adapter(Power power) { this._power = power; } /// <summary> /// 得到想要的电压 /// </summary> public void GetPower() { _power.GetPower220V(); Console.WriteLine("得到手机的充电电压!"); } } }
Client.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AdapterPattern.Practical.ObjectAdapter { public class Client { static void Main(string[] args) { Console.WriteLine("手机:"); ITarget t = new Adapter(new Power()); t.GetPower(); } } }
5、适配器模式应用分析
适配器模式适用情形:
◊ 当适用一个已存在的类,而它的接口不符合所要求的情况;
◊ 想要创建一个可以复用的类,该类可以与原接口的类协调工作;
◊ 在对象适配中,当要匹配数个子类的时候,对象适配器可以适配它们的父类接口。
适配器模式特点:
类适配器
◊ 使得Adapter可以重定义Adaptee的部分行为。因为Adapter是Adaptee的一个子类;
◊ 仅仅引入了一个对象,并不需要额外的指针间接得到Adaptee。
对象适配器
◊ 允许一个Adapter与多个Adaptee同时工作。Adapter也可以一次给所有的Adaptee添加功能;
◊ 使得重定义Adaptee的行为比较困难。需要生成一个Adaptee的子类,然后使Adapter引入这个子类而不是引用Adaptee本身。