类适配器到对象适配器

时间:2017-04-25 06:42:00

标签: c++

我试图将此代码转换为对象适配器,但由于我仍然试图完全理解这一点,所以我找不到正确的方法。

这是我在C ++中找到的唯一的适配器代码,其他代码通常不完整,仅显示适配器部分,所以我也发现很难编写自己的代码。

网站上的其他答案没有帮助。如果有人可以在Object Adapter中重写它并向我解释究竟有什么区别,我会非常感激

#include <iostream>

using namespace std;

typedef int Coordinate;
typedef int Dimension;

// Desired interface
class Rectangle
{
  public:
    virtual void draw() = 0;
    };

// Legacy component
class LegacyRectangle
{
  public:
    LegacyRectangle(Coordinate x1, Coordinate y1, Coordinate x2, Coordinate y2)
    {
        x1_ = x1;
        y1_ = y1;
        x2_ = x2;
        y2_ = y2;
        cout << "LegacyRectangle:  create.  (" << x1_ << "," << y1_ << ") => ("<< x2_ << "," << y2_ << ")" << endl;
    }
    void oldDraw()
    {
        cout << "LegacyRectangle:  oldDraw.  (" << x1_ << "," << y1_ << 
          ") => (" << x2_ << "," << y2_ << ")" << endl;
    }

  private:
    Coordinate x1_;
    Coordinate y1_;
    Coordinate x2_;
    Coordinate y2_;
};

// Adapter wrapper
class RectangleAdapter: public Rectangle, private LegacyRectangle
{
  public:
    RectangleAdapter(Coordinate x, Coordinate y, Dimension w, Dimension h):
      LegacyRectangle(x, y, x + w, y + h)
    {
        cout << "RectangleAdapter: create.  (" << x << "," << y << 
          "), width = " << w << ", height = " << h << endl;
    }
    virtual void draw()
    {
        cout << "RectangleAdapter: draw." << endl;
        oldDraw();
    }
};

int main()
{
  Rectangle *r = new RectangleAdapter(120, 200, 60, 40);
  r->draw();
}

2 个答案:

答案 0 :(得分:0)

RectangleAdapter与LegacyRectangle的关系应为&#34; has-a&#34;而不是&#34;是-a&#34;。

class RectangleAdapter: public Rectangle
{
  public:
    RectangleAdapter(Coordinate x, Coordinate y, Dimension w, Dimension h):
      legacyRectangle(x, y, x + w, y + h)
    {
        cout << "RectangleAdapter: create.  (" << x << "," << y << 
          "), width = " << w << ", height = " << h << endl;
    }
    virtual void draw()
    {
        cout << "RectangleAdapter: draw." << endl;
        legacyRectangle.oldDraw();
    }
private:
    LegacyRectangle legacyRectangle;
};

注意:我没有测试它

答案 1 :(得分:0)

  

这是我在C ++中找到的唯一的适配器代码,其他代码通常不完整,仅显示适配器部分,所以我也发现很难编写自己的代码。

嗯,它工作得很好......

  

[...]我仍然试图完全理解这个[...]

所以我认为这将有助于详细解释这个例子......

需要此类适配器类的问题通常是您希望将某些遗留代码集成或用于您自己的API - 但您不能或不想修改该遗留代码。该方案的一种变体是使用两个不同的不兼容的 API。

现在的想法是提供一个&#34;转换&#34;的适配器/包装器类。将一个API的对象放入另一个API的对象中(让我们继续使用旧方案,然后将遗留API对象转换为您自己的API对象)。

如果您现在使用组合或私有继承(组合是可取的,请参阅静态答案的评论中的链接)并不是真正的重点。重要的是,您的适配器/包装器类以适当的方式合并遗留对象,以便它可以访问所需的任何内容。

基本思想是适配器将使用遗留类提供的功能模拟为基类。

回到例子:

class Rectangle;

抽象基类。它定义了任何Rectangle类应提供的接口(在这种情况下:draw函数,它是纯虚拟的,即没有实现)。你自己的类 - 我们可以调用它OrdinaryRectangle(没有更好的想法 - 自己发明一些东西......) - 只需继承Rectangle基类并根据需要实现draw函数。

按照这个例子,您将定义与您自己的界面相同的方式并为您提供实现 - 或者您已经拥有。可能,您已经完成了自己的类的实现,但您可能还需要将公共接口提取到新的基类中。好的,渐渐远去......

class LegacyRectangle;

该类来自其他/遗留API。您可能会从遗留API中获取实例并将其反馈到以后。将这些实例转换为您自己的API并返回(例如,通过在Rectangle和转换运算符中提供适当的构造函数) - 替代方案 - 可能因任何原因而太昂贵(运行时开销,编码工作......)。所以你包装另一个类,假装是你自己的矩形实现的一个实例,但在内部使用传统的矩形。

class RectangleAdapter : public Rectangle, private LegacyRectangle

好的,示例使用私有继承,所以我会跟随,尽管在另一个答案中讨论了所有...

从Rectangle公开继承(必须!必须!)普通的矩形也是必要的,以便能够处理RectanlgeAdapter,就好像它是一个普通的矩形(技术上不正确:更好:因为两者都从Rectangle继承,两者都可以被视为这样 - 无论你实际拥有哪种情况 - 在大多数情况下,你甚至都不知道!)。

私有地从LegacyRectangle继承(或者最好具有内部成员),为您提供遗留API对象的内部实例。

构造函数;很好,我会省略一个解释......但是:你可能想为你的LegacyRectangle添加复制和移动构造函数(有点危险的措辞,通常,这些术语适用于复制/移动你自己的实例class - 但是你会看到) - 如果LegacyRectangle本身提供了这样的构造函数(在经典意义上),这是特别的(仅?)有趣:

RectangleAdapter(LegacyRectangle const& lr) : LegacyRectangle(lr) { }
RectangleAdapter(LegacyRectangle&& lr) : LegacyRectangle(std::move(lr)) { }

(上面不完整,但应该足以说明!)

virtual void draw()
{
    cout << "RectangleAdapter: draw." << endl;
    oldDraw();
}

我们处于核心位置 - 我们使用传统API实现自己的API接口。在这个例子中,这很简单 - 我们只使用oldDraw()函数。实际上,这可以实现任意复杂性。只是为了更多地了解它:想象一下,没有oldDraw,而是drawBorderfillInterior函数。然后,您必须在自己的draw函数中使用它们。

这是它变得非常困难的部分。如果你有问题,你需要更具体,我们需要知道确切的szenario和详细的问题,以帮助你...看看how to ask a good question和{{ 3}}之前......