一、引言
在实际的开发过程中,由于应用环境的变化(例如使用语言的变化),我们需要的实现在新的环境中没有现存对象可以满足,但是其他环境却存在这样现存的对象。那么如果将“将现存的对象”在新的环境中进行调用呢?解决这个问题的办法就是我们本文要介绍的适配器模式——使得新环境中不需要去重复实现已经存在了的实现而很好地把现有对象(指原来环境中的现有对象)加入到新环境来使用。
二、适配器模式的详细介绍
2.1 定义
下面让我们看看适配器的定义,适配器模式——把一个类的接口变换成客户端所期待的另一种接口,从而使原本接口不匹配而无法一起工作的两个类能够在一起工作。适配器模式有类的适配器模式和对象的适配器模式两种形式,下面我们分别讨论这两种形式的实现和给出对应的类图来帮助大家理清类之间的关系。
2.2 类的适配器模式实现
在这里以生活中的一个例子来进行演示适配器模式的实现,具体场景是: 在生活中,我们买的电器插头是2个孔的,但是我们买的插座只有三个孔的,此时我们就希望电器的插头可以转换为三个孔的就好,这样我们就可以直接把它插在插座上,此时三个孔插头就是客户端期待的另一种接口,自然两个孔的插头就是现有的接口,适配器模式就是用来完成这种转换的,具体实现代码如下:
/// <summary>
/// 三个孔的插头,也就是适配器模式中的目标角色
/// </summary>
public interface IThreeHole
{
void Request();
}
/// <summary>
/// 两个孔的插头,源角色——需要适配的类
/// </summary>
public abstract class TwoHole
{
public void SpecificRequest()
{
Console.WriteLine("我是两个孔的插头");
}
}
/// <summary>
/// 适配器类,接口要放在类的后面
/// 适配器类提供了三个孔插头的行为,但其本质是调用两个孔插头的方法
/// </summary>
public class PowerAdapter : TwoHole, IThreeHole
{
/// <summary>
/// 实现三个孔插头接口方法
/// </summary>
public void Request()
{
// 调用两个孔插头方法
this.SpecificRequest();
}
}
三、适配器模式的优缺点
在引言部分已经提出,适配器模式用来解决现有对象与客户端期待接口不一致的问题,下面详细总结下适配器两种形式的优缺点。
类的适配器模式:
优点:
可以在不修改原有代码的基础上来复用现有类,很好地符合 “开闭原则”
可以重新定义Adaptee(被适配的类)的部分行为,因为在类适配器模式中,Adapter是Adaptee的子类
仅仅引入一个对象,并不需要额外的字段来引用Adaptee实例(这个即是优点也是缺点)。
缺点:
用一个具体的Adapter类对Adaptee和Target进行匹配,当如果想要匹配一个类以及所有它的子类时,类的适配器模式就不能胜任了。因为类的适配器模式中没有引入Adaptee的实例,光调用this.SpecificRequest方法并不能去调用它对应子类的SpecificRequest方法。
采用了 “多继承”的实现方式,带来了不良的高耦合。
对象的适配器模式
优点:
可以在不修改原有代码的基础上来复用现有类,很好地符合 “开闭原则”(这点是两种实现方式都具有的)
采用 “对象组合”的方式,更符合松耦合。
缺点:
使得重定义Adaptee的行为较困难,这就需要生成Adaptee的子类并且使得Adapter引用这个子类而不是引用Adaptee本身。
四、使用场景
在以下情况下可以考虑使用适配器模式:
系统需要复用现有类,而该类的接口不符合系统的需求
想要建立一个可重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。
对于对象适配器模式,在设计里需要改变多个已有子类的接口,如果使用类的适配器模式,就要针对每一个子类做一个适配器,而这不太实际。