适配器模式

适配器模式分为两种:类适配器模式和对象适配器模式。

类适配器模式需要用到多重继承机制(C++支持)。

然而Java/C#等语言不支持多重继承,那么可以采用对象适配器模式。

本文首先讲解类适配器模式在C++中的实现,然后讲解对象适配器模式在Java中的实现。

背景

我们有一个绘图应用,可以在屏幕上绘制一些形状。该应用首先会获得该形状占据的区域大小,然后将形状绘制在此区域内。

clip_image001

客户端代码:

int main(int argc, char** argv)
{
    Shape* shape = new Shape();

    //获取该形状占据的矩形区域,以便于确定在哪个区域绘制该形状
    Rect* boundingBox = shape->BoundingBox();

    //绘制该形状
    /****/

    return 0;
}

现在我们引用了一个第三方库,里面有TextView类。

clip_image001[4]

我们希望可以把TextView绘制在屏幕上,可是TextView类没有BoundingBox方法,因此我们不知道TextView占据的区域形状也就无法直接绘制该类。解决方案如下:

  • 修改TextView类的代码,以增加BoundingBox方法。(不可行,我们可能无法获得源码)
  • 用适配器模式。(对,下面我们来详细讲解)

适配器模式

适配器模式就像手机适配器(手机充电器)可以把220V的交流电转换为手机可以直接使用的5V直流电。我们先介绍下适配器模式中的几个术语:

  • 目标类(Target):5V直流电
  • 适配者(Adaptee): 220V交流电
  • 适配器(Adapter):手机充电器

我们知道客户端已经可以在屏幕上绘制Shape对象。然而不知道如何绘制TextView对象,因为它没有BoundingBox方法。我们考虑新建一个TextShape类,其含有BoundingBox方法。

Shape是目标类(Target)。

TextView是适配者(Adaptee)。

TextShape是适配器(Adapter)。

clip_image001[6]

(图为类适配器模式)

image

(图为对象适配器模式)

C++实现代码(类适配器模式)

可以想象,适配器模式的关键是Adapter如何将Adaptee转换为Targe。如何转换取决于具体的应用。

Adapter代码:

Rect* TextShape::BoundingBox() const
{
    //一个中文字符占用2个相对宽度
    //一个英文字符占用1个相对宽度
    //这里为了简单起见,一律认为是1个相对宽度
    float width = this->GetText().length();
    float heigh = 1.0;
    //高度和宽度都要乘上字体大小比例
    return new Rect(
            new Point(0, 0), 
            new Point(width * this->GetFontSize(), heigh * this->GetFontSize())
        );
}

客户端代码:

//采用类适配器模式的话,客户端代码会比较容易
//如果采用对象适配器模式,客户端的代码会多一点
int main()
{
    Shape* shape = new TextShape();
    Rect* boundingBox = shape->BoundingBox();

    return 0;
}

Java实现代码(对象适配器模式)

适配器代码:

//由于不支持多继承
//需要在构造函数传入adaptee对象
public class TextShape extends Shape{
    private TextView textView;
    public TextShape(TextView textView) {
        this.textView = textView;
    }
    
    @Override
    public Rectangle boundingBox() {
        //根据textView的内容计算占据的区域大小
        //这里需要较复杂的代码
        return null;
    }
}

客户端代码:

public class Client {
    public static void main(String[] args) {
        TextView textView = new TextView();
        Shape shape = new TextShape(textView);
        
        shape.boundingBox();
    }
}
原文地址:https://www.cnblogs.com/dongchen/p/5111132.html