我作为一家公司的计算机视觉部门的软件开发人员已经工作了一年。我的主要工作是将第三方软件集成到一个框架中,所以我通常最终编写包装库,因为很多这个第三方软件不能按我们希望的方式工作(不是线程安全,a *中的痛苦) *使用等。)。
通常我只是包装整个库并保护对具有互斥的库的调用(线程安全在某种程度上是大多数外部库的主要问题)。我非常喜欢这样做,因为它会让你进入很多有趣的场景,你会看到很多有趣的代码。但是,我经常认为我没有正确地做到这一点,或者我的实施并不是很好。我觉得我缺乏某种关于如何正确地做这样的事情的设计知识。
基本上我想知道是否有任何关于设计正确的'API ontop of broken API'的良好指导或提示,或者如果这总是一定非常hackish和丑陋。
答案 0 :(得分:5)
我将在前几天引用另一个问题的答案:
如果是,请继续做你正在做的事情。
作为替代
确保您的新API包含预期功能以及原始版本的常规或意外功能。同时确保它呈现“适合目的”的重新呈现。看看FOSS项目中C库的C ++包装,例如GTK / GTK for C ++(它只包装前者)。
如果API被破坏,修复它并提交补丁......加入第三方(我假设有权访问来源意味着他们不介意这一点)...你可以重写他们的一些API是'包装友好',并建议他们合并一些变化。如果有问题,请修理它。
对此并不多,只需用A包裹A并确保B执行A应该使用的或用于。
答案 1 :(得分:2)
我唯一能添加到Aiden's response的是你还应该寻找替换需要使用RAII技术进行显式初始化和终止的代码。当我面对提供API的外观时,我似乎总是遇到一个看起来像这样的类:
struct ADVERTISER {
/* a bunch of members here */
};
void adv_Initialize(ADVERTISER *adv, /* a bunch of arguments */);
void adv_DoStuff(ADVERTISER *adv);
void adv_Terminate(ADVERTISER *adv);
我已经看到它以下列方式包装在C ++类中:
namespace wrapper {
class Advertiser {
public:
Advertiser(): inited_(false) {}
void initialize(/* a bunch of arguments */) {
terminate();
adv_Initialize(&adv_, ...);
inited_ = true;
}
void doStuff() {
validate();
adv_DoStuff(&adv_);
}
void terminate() {
if (inited_) {
adv_Terminate(&adv_);
inited_ = false;
}
}
protected:
void validate() {
if (!inited_) {
throw std::runtime_error("instance is not valid");
}
}
private:
ADVERTISER adv_;
bool inited_;
};
}
问题是Advertiser
类并没有真正使API更容易使用,甚至更清洁恕我直言。如果遇到这样的情况,那么:
我的目标是确保我呈现/创建/包装的任何API都适用于我们现有的编码风格。我也试图将API变成比现在更多的OO样式。我已经看到了一些我称之为面向对象的C 的内容,就像我上面提到的那样。如果你想让它们真正适合C ++,那么那就真正面向对象并利用C ++给你的东西: