设计模式学习总结:适配器模式(Adapter)

本文介绍适配器模式的应用场景及其实现方式,包括类适配器和对象适配器两种结构,通过具体代码示例展示如何将火鸡对象转换为鸭子对象,以便在现有系统中使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 场景分析

假设我们先有一个鸭子类型如下:

class Duck
{
public:
    virtual void quack() = 0;
    virtual void fly() = 0;
};

class MallardDuck : public Duck
{
public:
    void quack() override
    {
        cout << "mallard duck quack" << endl;
    }
    void fly() override
    {
        cout << "mallard duck fly" << endl;
    }
};

然后我们又有了一个火鸡类型:

class Turkey
{
public:
    virtual void gobble() = 0;
    virtual void fly() = 0;
};

class WildTurkey : public Turkey
{
public:
    void gobble() override
    {
        cout << "wild turkey gobble" << endl;
    }

    void fly() override
    {
        cout << "wild turkey fly" << endl;
    }
};

现在假设我们缺少鸭子对象,想用一些火鸡对象来代替,显而易见由于火鸡和鸭子的接口不同所以我们不能公然拿来用,所以这时我们就需要一个适配器,如下:

class TurkeyAdapter : public Duck
{
public:
    //构造函数,将一只火鸡“装扮”成一只鸭子
    TurkeyAdapter(Turkey *turkey) :_turkey(turkey){}

    void quack() override
    {
        _turkey->gobble();
    }

    void fly() override
    {
        _turkey->fly();
    }

private:
    Turkey *_turkey;
};

现在我们来使用这只火鸡冒充的鸭子

int main()
{
    //原本是一只野火鸡
    auto wildTurkey = new WildTurkey();
    //现在变成了一只鸭子
    auto duck = new TurkeyAdapter(wildTurkey);
    //鸭子会“呱呱叫”以及“飞行”
    duck->quack();
    duck->fly();

    system("PAUSE");
    return 0;
}

运行结果如下
这里写图片描述

2.意图

将一个类接口转换成另一个类的接口,使原本接口不兼容的两个类可以合作无间。

3.适用性

  1. 你想使用一个已经存在的类,而它的接口不符合你的需求。
  2. 你想创建一个可以复用的类,该类可以与其他不想关的类或不可预见的类协同工作。
  3. 你想使用一些子类,但不可能对每一个类都子类化以匹配它们的接口,则可以使用适配器适配它们的父类接口。

4.结构

适配器结构有两种。
第一种,类适配器使用多重继承对一个接口与另一个接口进行适配,如下图:
这里写图片描述
第二种,对象匹配器依赖于对象组合,如下图:
这里写图片描述
Target:程序实际需要使用的类型
Client:使用Target的用户
Adaptee:包含需要被适配的接口
Adapter:适配后的产物
我们可以看到我们使用多重继承来完成适配,也可以通过在适配器中包含一个Adaptee对象来完成适配,前面鸭子的例子中使用的是第二种适配方法。

5.效果

类适配器与对象适配器有不同的权衡。
类适配器使得Adapter可以重定义Adaptee的部分行为,但是它不能适配Adaptee的所有子类。
对象适配器使得Adapter可以适配Adaptee的所有子类,但不能重定义Adaptee的行为。

6.实现

尽管Adapter模式的实现方式通常简单直接,但是仍然需要注意以下问题:
1>在使用C++实现适配器时,Adapter类应该采用公有方式继承Target,而采用私有方式继承Adaptee类。因此Adapter类应是Target的子类型,但不是Adaptee类的子类型。

7代码示例

class Point
{
public:
    Point(float width, float height) :_width(width), _height(height){}
private:
    float _width;
    float _height;
};

class Shape
{
public:
    Shape(){}
    virtual void getBoundingBox(Point &bottomLeft, Point &topRight);
};

class TextView
{
public:
    TextView();
    void getOrigin(float &x, float &y) const;
    void getExtent(float &width, float &height) const;
    virtual bool isEmpty() const;
};

class TextShape : public Shape, private TextView
{
public:
    TextShape(){}
    void getBoundingBox(Point &bottomLeft, Point &topRight) override
    {
        float bottom, left, width, height;
        getOrigin(bottom, left);
        getExtent(width, height);

        bottomLeft = Point(bottom, left);
        topRight = Point(bottom + height, left + width);
    }

    bool isEmpty() const
    {
        return TextView::isEmpty();
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值