c++ - 使用接口(interface)包装库而不需要向下转换

标签 c++ oop interface

假设我的项目使用了一个库 LibFoo,它通过许多类提供其功能,例如 FooAFooB。现在,有许多类似的库(例如,提供 BarABarBLibBar)提供与 LibFoo 相同的功能 并且我希望我的项目的用户能够选择使用哪个库,最好是在运行时。

为此,我创建了一个“包装层”,它定义了我期望从库中获得的接口(interface)。在我的示例中,该层包含两个接口(interface):IfaceAIfaceB。然后,对于我想要支持的每个库,我创建一个“实现层”,使用其中一个库来实现接口(interface)。

我现在的问题在于如何很好地实现实现层。为了演示我的问题,考虑我们有以下接口(interface)(用 C++ 显示,但应该适用于类似的语言):

class IfaceA
{
public:
    virtual void doSomethingWith(IfaceB& b) = 0;
    ...
};

class IfaceB
{
    ...
};

LibFoo 实现层中的类将保存来自LibFoo 相应类的对象。接口(interface)中的操作应该使用这些对象来实现。因此(请原谅我的可怕名字):

class ConcreteAForFoo : public IfaceA
{
public:
    void doSomethingWith(IfaceB& b) override
    {
        // This should be implemented using FooA::doSomethingWith(FooB&)
    }

private:
    FooA a;
};

class ConcreteBForFoo : public IfaceB
{
public:
    FooB& getFooB() const
    {
        return b;
    }

private:
    FooB b;
};

问题在于实现 ConcreteAForFoo::doSomethingWith:它的参数类型为 IfaceB& 但我需要访问 ConcreteBForFoo 的实现细节来能够正确执行该方法。我发现这样做的唯一方法是到处使用丑陋的向下转型:

void doSomethingWith(IfaceB& b) override
{
    assert(dynamic_cast<ConcreteBForFoo*>(&b) != nullptr);
    a.doSomethingWith(static_cast<ConcreteBForFoo&>(b).getFooB());
}

由于不得不向下转换通常被认为是代码异味,我不禁想到应该有更好的方法来做到这一点。还是我一开始就设计错了?

TL;DR

给定一层相互依赖的接口(interface)(其中一个接口(interface)中的方法接收对其他接口(interface)的引用)。这些接口(interface)的实现如何在不向下转换或在接口(interface)中暴露这些细节的情况下共享实现细节?

最佳答案

看起来很经典double dispatch用例。

class IfaceA
{
public:
    virtual void doSomethingWith(IfaceB& b) = 0;
    ...
};

class IfaceB
{
    virtual void doSomethingWith(IfaceA & a) = 0;
    ...
};

struct ConcreteAForFoo : public IfaceA {
    virtual void doSomethingWith (IfaceB &b) override {
        b.doSomethingWith(*this);
    }
};

struct ConcreteBForFoo : public IfaceB
{
    virtual void doSomethingWith(IfaceA & a) override {
        //b field is accessible here
    }

private:
    FooB b;
};

可以改变 IfaceB::doSomethingWith 签名以获得耦合和访问级别之间的最佳平衡(例如,ConcreteAForFoo 可以用作参数以通过紧密耦合来访问其内部)。

关于c++ - 使用接口(interface)包装库而不需要向下转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27224764/

相关文章:

c++ - 从计算机向计算机发送 XML 数据 - Qt

C++ 行和列矩阵操作

c++ - 将 x86 代码注入(inject) x64 进程

C++将新数组传递给函数的指针

javascript - 如何将一个html文件添加到另一个html文件中(附示例)

python - 如何从Python对象中检查方法是否存在

java - 在接口(interface)中添加默认和静态方法的原因

c# - 处理包装 IDispatch COM 接口(interface)的 c# 接口(interface)

Objective-C:从类引用创建实例

pointers - 隐藏 nil 值,理解为什么 Go 在这里失败