简体   繁体   English

包装第三方库的建议

[英]Advice on wrapping third party libraries

I have been working a year now as a software developer for a at the computer-vision department of a company. 我已经在一家公司的计算机视觉部门工作了一年,担任软件开发人员。 My main job is integration of third-party software into a framework, so i usually end up writing wrapper libraries because a lot of this third party software does not work the way we want it to work(not thread safe, pain in the a** to use etc.). 我的主要工作是将第三方软件集成到框架中,所以我通常最终会编写包装器库,因为很多此类第三方软件无法按我们希望的方式工作(线程安全,痛苦,* *使用等)。

Normally i just wrap the whole library and guard the calls to the library with mutual exclusions(thread safety is somehow the major problem with most extern libraries). 通常,我只是包装整个库,并通过互斥来保护对库的调用(某种程度上,线程安全是大多数extern库的主要问题)。 I really enjoy doing this, as it puts you into a lot of interesting situations and you get to see a lot of interesting code. 我真的很喜欢这样做,因为它会使您陷入很多有趣的情况,并且您会看到很多有趣的代码。 However i often think that i am not doing it properly or that my implementation is not really good. 但是我经常认为我做得不好,或者我的实现不是很好。 I feel like i am lacking some sort of design knowledge on how to properly do stuff like that. 我觉得我缺乏某种如何正确地做这类事情的设计知识。

Basically i want to know if there are any good guidelines or hints about designing a proper 'API ontop of broken API', or if this is always bound to be quite hackish and ugly. 基本上,我想知道是否有关于设计正确的“破碎的API之上的API”的良好指南或提示,或者这总是很黑且丑陋。

I will quote an answer to another question on here the other day : 前几天,我将在这里引用另一个问题的答案

  1. Does your current method pass testing? 您当前的方法是否通过测试?
  2. Is it fast enough? 够快吗?

If yes, keep doing what you are doing. 如果是,请继续做您正在做的事情。

As an alternative 作为备选

Just ensure your new API encompasses both the intended functionality and the conventional or accidental functionality of the original. 只要确保您的新API既包含预期的功能,又包含原始功能的常规偶然功能即可。 Also ensure it presents a 'fit-for-purpose' re-presentation. 还要确保它呈现“适合目的”的重新表示。 Take a peek at the C++ wrapping of C libraries in FOSS projects such as GTK/GTK for C++ (which just wraps the former). 看看FOSS项目中C库的C ++包装,例如GTK / GTK for C ++(仅包装前者)。

If the API is broken, fix it and submit a patch ... get involved with the third-parties (I am assuming having access to the source means they won't mind this) ... You could re-write some of their API to be 'wrapping friendly' and suggest they merge some changes. 如果API损坏,请对其进行修复并提交补丁...介入第三方(我假设可以访问源意味着他们不介意此事)...您可以重写其中的一些内容API是“包装友好的”,并建议它们合并一些更改。 If there is a problem, be the one to fix it. 如果有问题,请先解决。

Not much to it, just wrap A with B and ensure B does what A was supposed to, or is used for. 没什么大不了的,只需用B包裹A并确保B做到了A的预期或用途。

The only thing that I can add to Aiden's response is that you should also look to replace code that requires explicit initialization and termination with RAII techniques. 我可以添加到艾登的回复中的唯一一件事是,您还应该考虑使用RAII技术替换需要显式初始化和终止的代码。 When I've been faced with providing a façade over APIs, I always seem to run into a class that looks like: 当我面对提供有关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);

I've seen this wrapped in a C++ class in the following manner: 我已经看到它以下列方式包装在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_;
  };
}

The problem is that the Advertiser class doesn't really make the API any easier to use or even cleaner IMHO. 问题在于Advertiser类实际上并没有使API变得更易于使用甚至更清洁 If you run into cases like this, then: 如果遇到这种情况,则:

  1. Use a fully parameterized constructor to ensure that invalid instances do not exist 使用完全参数化的构造函数以确保无效实例不存在
  2. Clean up all resources in the destructor 清理析构函数中的所有资源
  3. Write a copy constructor and assignment operator if they make sense or make them private and don't implement them. 如果有意义, 将其设为私有并且不实现它们,请编写一个复制构造函数和赋值运算符。

My goal is to make sure that whatever API I am presenting/creating/wrapping works with our existing coding style. 我的目标是确保我呈现/创建/包装的任何API都可以使用我们现有的编码风格。 I also try to bend the API into a more OO style than it may currently be in. I have seen a number of what I call object-oriented C like the one that I presented above. 我还尝试将API弯曲成比当前可能更多的OO样式。我已经看到了许多我称为面向对象的C,就像我上面介绍的那样。 If you want to make them really fit into C++, then make then truly object-oriented and take advantage of what C++ gives you: 如果您想使它们真正适合C ++,那么就使它们真正成为面向对象的,并利用C ++给您的好处:

  • Be careful to manage any state variables. 小心管理任何状态变量。
  • If actions like copying don't make sense, then hide them. 如果像复制这样的操作没有意义,请隐藏它们。
  • If there is any possibility of leaking resources, then find some way to prevent it from happening (usually employing RAII helps). 如果有可能泄漏资源,请找到某种方法防止它发生(通常使用RAII会有所帮助)。
  • Restrict the creation of instances using constructors to eliminate invalid instances and other edge cases. 使用构造函数限制实例的创建,以消除无效实例和其他边缘情况。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM