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非常复杂,编写这样的工具会非常昂贵.
您认为解决此类问题的最佳方法是什么?也许你已经处理过这样的事情并且可以提供良好的提示?我们期待着您的回答!