C++循环依赖使用类如何重构



我正在处理C++中的一个循环依赖问题。

情况如下:

libA.so:
    - Body.cpp
    - Header.cpp
    - DataObject.cpp
    - DataObject::read(boost::asio::streambuf* data)
      {
          boost::asio::streambuf data;
          ....
          body = (new DataConverter<Body>)->convert(&data);
          header = (new DataConverter<Header>)->convert(&data);
      }
  libB.so:
      - DataConverter.cpp
          -> DataConverter<T>
          -> T* DataConverter<T>::convert(boost::asio::streambuf* data)
  libA.so <-> libB.so

存在循环依赖关系,因为libA使用libB中的Converter类,而libB现在需要了解需要转换的libA的对象类型,因为DataConverter::convert返回Body或Header对象。

我曾想过用正向声明来解决这个问题,但这对我来说似乎不是最干净的解决方案。总之,我的计划是提供一个可扩展的DataConverter解决方案。

你们会建议什么作为最佳实践?完全不同的设计也很受欢迎:)

最佳,Sebastian

如果您需要一个类模板DataConverter,那么它不能是任何编译库的一部分。它必须通过包含文件提供。一旦将DataConverter代码放入libAlibB都使用的标头中,循环依赖关系就会消失。

您的设计似乎有缺陷。如果名为A和B的两个库相互依赖,则意味着它们必须始终一起发货。如果它们必须始终一起发货,这意味着它们在逻辑上是同一接口的一部分。这意味着事实上,你只有一个图书馆。

没有足够的信息来说明什么是最好的解决方案,但这里有一些提示:

  1. 合并这些库
  2. 使一个库依赖于另一个库,例如,通过将DataConverter移动到libA
  3. 创建一个实用程序库,依赖于这两个
  4. 使用模板或虚拟类在libB中创建一个适当的接口,并使libA依赖于libB。后者(虚拟类)很可能是动态链接库中更好的选择

您可能想要创建定义接口的抽象基类,并相互隐藏实现(派生类)。

一些替代方案:

  1. DataConverter是一个完全通用的实现,它将在编译时用适当的类型在libA.so中实例化。这是一个典型的c++式解决方案。来自libA(或其他)的"可转换"类型必须满足某些Convertable概念,而DataConverter的完全模板化实现将使用

  2. 依赖反转,如JohnB所提出的。您基本上可以实现相同的目标,但需要在运行时使用接口、实现和注册/解析。还有很多工作要做,但可扩展、ABI可实现、可部署为库等

  3. 两者的某种巧妙结合,类似于Boost.Serialization。然而,这很难实现,也很容易打破。。。

相关内容

  • 没有找到相关文章

最新更新