如何为遗留API /框架(C++宏与C++模板与代码生成器)实现大量复杂包装器?

now*_*waq 10 c++ macros templates code-generation legacy-code

我们使用VC6编译器在C++中实现的非常古老的遗留系统.现在我们正在重构代码.我们还切换到了VC9编译器.

我们使用外部专有框架,这也是遗留代码,而不是单元可测试的.为了使我们的代码单元可测试,我们为框架类引入了接口和包装器(提示:请参阅Martin Fowler的"使用遗留代码"):

在此输入图像描述

现在我们依赖于接口.包装器调用框架方法,我们可以愉快地在单元测试中使用模拟.

在这里,我们来解决我们的问题......

框架类包含许多需要包装和模拟的方法.为了实现这一目标,我们的供应商团队编写了一个API,它使用C++宏生成接口,包装器和模拟器实现.

包装头文件的示例:

class PlanWrapper : public IPlan
{
  // ... 
  WRP_DECLARE_DEFAULTS(FrameworkPlan); // macro
  WRP_DECLARE_CSTR_ATTR(FrameworkPlanLabel); // macro
  // ...
};
Run Code Online (Sandbox Code Playgroud)

宏WRP_DECLARE_CSTR_ATTR的定义如下:

#define WRP_DECLARE_CSTR_ATTR(AttrName) \
    virtual bool set##AttrName (LPCTSTR Value_in); \
    virtual bool get##AttrName (CString& Value_out); \
    virtual bool unset##AttrName (); \
    virtual bool isSet##AttrName ()
Run Code Online (Sandbox Code Playgroud)

包装器cpp文件的示例:

#include "StdAfx.h"

using namespace SomeNamespace;

WRP_IMPLEMENT_MODDICOM_DEFAULTS(FrameworkPlan)
WRP_IMPLEMENT_W_CSTR_ATTR (FrameworkPlan,FrameworkType1, FrameworkPlanLabel)
// ...
Run Code Online (Sandbox Code Playgroud)

宏WRP_IMPLEMENT_W_CSTR_ATTR的定义如下:

#define WRP_IMPLEMENT_W_CSTR_ATTR(ClassName,AtrTypeObj,AttrName) \
    bool ClassName##Wrapper::set##AttrName (LPCTSTR Value_in) { \
            AtrTypeObj aValue = Value_in; \
        FrameworkLink<ClassName> convertedObj = NULL_LINK; \
        framework_cast(convertedObj, m_Object); \
        return convertedObj != NULL_LINK ? \
                       convertedObj->set##AttrName (aValue) : false; \
    }
    // ...
Run Code Online (Sandbox Code Playgroud)

我们有一堆更复杂的东西,但我认为你明白了.

API的问题在于它非常复杂,不可读,不可调试且无法测试.

我们想提出一个更好的机制来实现同一目标.我们的想法是使用新编译器附带的一些高级功能,如高级模板,类型列表,特征等.

使用模板我们几乎可以实现我们的目标,但我们仍然坚持使用方法名称.我们可以推广类型,但我们如何处理属性名称?

我们还考虑过创建一个自动生成包装器+接口+模拟代码的工具.但是,我们的外部框架的API非常复杂,编写这样的工具会非常昂贵.

您认为解决此类问题的最佳方法是什么?也许你已经处理过这样的事情并且可以提供良好的提示?我们期待着您的回答!

Luc*_*lle 1

我想我会使用代码生成工具。我可能会制作一些简单的实用程序:一个用于生成与遗留框架的类相对应的接口,一个用于生成包装器,一个用于生成模拟对象(或至少一个骨架)。

这意味着有某种方法来解析遗留框架的代码。我会看一下Clang,或者可能只是在源文件上运行ctags并处理生成的标签。