将接口包裹在库中的类周围

  • 本文关键字:周围 接口 包裹 c++ c++17
  • 更新时间 :
  • 英文 :


在库中定义了一个类:

class fromLib{};

用作调用库中实现的方法的参数:

method_from_lib(const fromLib& from_lib){};

我想把这个方法包装在一个接口中

class Methods{
virtual invoke_method(const& genericArg)
} 

其中类别CCD_ 1是CCD_。

一个简单的实现是:

class MethodImpl: public Methods { 
invoke_method(const genericArg& arg) { 
method_from_lib(arg); // this is not going to work since the argument is not an instance of `fromLib` nor convertible nor does it inherit from it. 
}; 
}

在理想的情况下,我会使类fromLib直接继承自genericArg。然而,这是不可能的,因为这门课来自一个我真的不想碰的图书馆。

我该如何实现fromLib的包装器,它也是genericArg的实现。

这样做的动机如下:

库提供了一些带有签名method_from_lib(const fromLib& from_lib){};的方法,我们可能会使用,也可能不会使用。我们可能希望使用该方法或其他实现。如果我们使用其他实现,函数的参数也需要更改,因为参数fromLib与库提供的实现紧密耦合。

因此,为方法本身提供一个接口是很简单的,然而,这个问题的目的是如何将参数fromLib推广到某个接口中。这样我们的界面就会像一样

类方法{虚拟invoke_method(const&genericArg)}

当我们想使用库来实现这个案例时,实现相当容易——我们只需从库中调用方法,即

invoke_method(const TYPE& arg) { 
method_from_lib(arg); 
}; 

现在,正如您所看到的,实现这个方法要么需要genericArg0是genericArg,要么需要从它继承的某个类。这里的问题是,method_from_lib需要类型fromLib,我们不能直接将其作为genericArg的子级,因为该类型包含在第三方库中

我想您正在寻找一个适配器。

https://refactoring.guru/design-patterns/adapter/cpp/example

用法示例:适配器模式在C++代码中非常常见。它是通常在基于一些遗留代码的系统中使用。在这种情况下,适配器使遗留代码能够与现代类一起使用。

标识:适配器可由构造函数识别,该构造函数不同抽象/接口类型的实例。当适配器接收到对其任何方法的调用,它将参数转换为适当的格式,然后将调用定向到一个或多个方法包裹对象的。

您声明不想接触fromLib类。假设fromLib所需的数据肯定是要执行的操作所必需的,那么您必须实现自己的结构,该结构包含所需数据。

然后可以将这个自己的结构传递给适配器。然后,适配器将把它传递给lib,并返回正确的结果。如果要切换出lib,则切换出适配器以使用新的lib。代码的其余部分将保持不变。

例如:

class fromLib{
int degrees;// You can't change this even if you'd want to use radians in your program.
}
struct myActualRequiredData {
double radians;// Choose something here which works well within your own program.
}
class MethodsTarget{
virtual invoke_method(const myActualRequiredData& data);
} 
class MethodsAdapter : public MethodsTarget{
virtual invoke_method(const myActualRequiredData& data) {
fromLib myFromLib = {
.degrees = radians * 360 / PI;// Or so. I currently don't care, not what your question is about. In any case, here's where you do all the work to speak the libraries language.
};
method_from_lib(myFromLib);
}
};
MethodsAdapter adapter;
adapter.invoke_method({
.radians = 0.2
});
// Oh look I found a better lib
class fromLib2{
std::string degrees;
}
class MethodsAdapter2 : public MethodsTarget {
virtual invoke_method(const myActualRequiredData& data) {
fromLib2 myFromLib = {
.degrees = std::string(radians * 360 / PI);
};
method_from_lib(myFromLib);
}
}
MethodsAdapter2 adapter2;
adapter.invoke_method({
.radians = 0.2
});

此示例表明,在使用适配器模式时,更改库将导致最小的调整。

如有必要,可与指向MethodsTarget的指针一起使用。但通常对于libs来说,仅仅拥有一个适配器类就足够了。无论如何,你不会热交换。

我建议使用组合并将成员传递到库调用中:

struct GenericArg{
fromLib member;
};
void wrapper(const GenericArg& arg){
method_from_lib(arg.member);
}

最新更新