Spiga

模式开发之旅(13):适配器模式

2010-07-28 11:08:36

适配器模式:将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

适配器模式有两种实现方式:类适配器和对象适配器。其中,类适配器使用继承关系来实现,对象适配器使用组合关系来实现。

// 类适配器: 基于继承
public interface ITarget 
{ 
    void F1();
    void F2();
    void Fc();
}
public class Adaptee
{ 
    public void Fa() 
    {
        //...
    } 
    public void Fb() 
    {
        //...
    }
    public void Fc()
    {
        //...
    }
}
public class Adaptor : Adaptee, ITarget 
{ 
    public void F1() 
    { 
        base.Fa(); 
    } 
    public void F2()
    {
        //...重新实现F2()...
    } 

    // 这里fc()不需要实现,直接继承自Adaptee,这是跟对象适配器最大的不同点
}

// 对象适配器:基于组合
public interface ITarget
{
    void F1();
    void F2();
    void Fc();
}
public class Adaptee
{
    public void Fa()
    {
        //...
    }
    public void Fb()
    {
        //...
    }
    public void Fc()
    {
        //...
    }
}
public class Adaptor : ITarget
{
    private Adaptee adaptee;
    public Adaptor(Adaptee adaptee)
    {
        this.adaptee = adaptee;
    }
    public void F1()
    {
        adaptee.Fa(); //委托给Adaptee
    }
    public void F2()
    {
        //...重新实现f2()... 
    }
    public void Fc()
    {
        adaptee.Fc();
    }
}

一般来说,适配器模式可以看作一种“补偿模式”,用来补救设计上的缺陷。应用这种模式算是“无奈之举”,如果在设计初期,我们就能协调规避接口不兼容的问题,那这种模式就没有应用的机会了。

那在实际的开发中,什么情况下才会出现接口不兼容呢?我总结下了下面这样 5 种场景:

  • 封装有缺陷的接口设计
  • 统一多个类的接口设计
  • 替换依赖的外部系统
  • 兼容老版本接口
  • 适配不同格式的数据

代理、适配器、桥接、装饰,这四个模式有何区别

代理、桥接、装饰器、适配器,这 4 种模式是比较常用的结构型设计模式。它们的代码结构非常相似。笼统来说,它们都可以称为 Wrapper 模式,也就是通过 Wrapper 类二次封装原始类。

尽管代码结构相似,但这 4 种设计模式的用意完全不同,也就是说要解决的问题、应用场景不同,这也是它们的主要区别。这里我就简单说一下它们之间的区别。

代理模式:代理模式在不改变原始类接口的条件下,为原始类定义一个代理类,主要目的是控制访问,而非加强功能,这是它跟装饰器模式最大的不同。

桥接模式:桥接模式的目的是将接口部分和实现部分分离,从而让它们可以较为容易、也相对独立地加以改变。

装饰器模式:装饰者模式在不改变原始类接口的情况下,对原始类功能进行增强,并且支持多个装饰器的嵌套使用。

适配器模式:适配器模式是一种事后的补救策略。适配器提供跟原始类不同的接口,而代理模式、装饰器模式提供的都是跟原始类相同的接口。