【问题标题】:Refactoring function calls while reducing code duplication of resulting class definitions重构函数调用,同时减少生成的类定义的代码重复
【发布时间】:2010-12-14 10:23:34
【问题描述】:

我有一个包含大约 400 个函数声明的头文件及其对应的包含定义的源文件。

为了在运行时用模拟替换实现,我想用对包含实现的对象的调用替换实现(指向实现的指针 - pImpl)。

这意味着我将拥有以下文件:

  • mainFile.h - 像以前一样包含方法声明(必须保留,因为我无法用客户端代码替换接口)
  • IImpl.h - 实现对象的抽象基(接口)
  • mainFile.cpp - 将包含方法定义,它会调用 IImpl* 上的相应方法
  • SpecificImpl.cpp - 包含具体实现的声明和定义
  • MockImpl.cpp - 包含测试期间使用的实现的声明和定义

这样做的主要问题是出现在主头文件和每个类定义中的 400 个方法声明重复。

有什么办法可以避免这种重复吗?我正在尝试使用宏,但随后包含的顺序变得过于具体......

【问题讨论】:

    标签: c++ refactoring


    【解决方案1】:

    这样的事情怎么样:

    //=======================================
    // Macro definition of method list
    //=======================================
    #define METHOD_LIST(ABSTRACT) \
        virtual void Foo1() ABSTRACT; \
        virtual void Foo2() ABSTRACT; \
        virtual void Foo3() ABSTRACT
    
    //=======================================
    // Declaration of Abstract base class
    //=======================================
    class IBase
    {
    public:
        METHOD_LIST( = 0);
    };
    
    //=======================================
    // Declaration of Specific
    //=======================================
    class CSpecific : public IBase
    {
    public:
        METHOD_LIST();
    };
    
    //=======================================
    // Declaration of Mock class
    //=======================================
    class CMock : public IBase
    {
    public:
        METHOD_LIST();
    };
    

    更新...

    如果你想让它更加宏隐,你可以将宏更改为:

    #define METHOD_LIST(VIRTUAL, ABSTRACT) \
        VIRTUAL void Foo1() ABSTRACT; \
        VIRTUAL void Foo2() ABSTRACT;
    

    这将允许您声明不属于任何对象的常规函数​​列表:

    对于抽象类:

    METHOD_LIST(virtual, =0)
    

    对于派生类:

    METHOD_LIST(virtual, ;)
    

    对于常规函数列表:

    METHOD_LIST(;, ;)
    

    如果你需要调试这个烂摊子,那么我建议使用'g++ -M'来查看预处理器的结果。

    【讨论】:

      【解决方案2】:

      使用纯虚拟类作为接口和具有重构支持的良好 IDE。

      纯虚拟类类似于 API 合约(在其他语言中有时称为接口)。您声明一个方法一次,然后在 3-4 个其他类中从它继承。您只需更改接口中的一个方法,它会在依赖类中发生更改......或者至少那些不会再编译并且您知道您也必须在那里进行更改。

      阅读更多关于此的信息,例如在wikipedia

      【讨论】:

      • 嗯,首先它是针对 C++ 的,所以不确定这些工具是否支持它...其次,问题不在于复制的体力劳动 - 它是 4-5 400line 的维护方法声明。
      • 是的,但是具体实现和模拟实现都需要实现所有/大部分方法,因此它们的标题仍然必须包含所有声明
      • @lk:删除了 ReSharper 引用,因为它确实不支持 C++。对不起。我让我的答案更清楚了......我希望。
      • @lk: 也许我还是搞错了……或者在过去的几年里我忘记了太多关于 C++ 的事情……必须检查,但我认为你不需要声明两个头文件,只有一个。顺便说一句:我正在以不同的方式添加新答案
      【解决方案3】:

      一种方法是使用重构工具;大多数现代 IDE 都有。例如,Eclipse CDT 有一个重构选项。 Gerd 也提出了一个建议。

      另一种方法是使用代码检测工具,如pin。这些工具主要用于分析,但可能适合您的目的。

      更新:

      如果您的问题不在于编写代码,而在于维护,我认为 pin 是一个不错的选择(运行时更改)。另一种方法是使用面向方面的编程。例如,Aspect C++

      【讨论】:

      • 再一次,问题不在于编写代码的工作——sed/perl 在这方面做得很棒! :-)
      【解决方案4】:

      编写一个小代码生成器,从主头文件中获取方法声明并将它们复制到 SpecificImpl 和 MockImpl 头文件中。

      【讨论】:

        【解决方案5】:

        如果这是一个常见问题,那么请学习使用模板,并研究通用/生成/元编程技术。 (兔子洞很深)

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2017-08-25
          • 1970-01-01
          • 2013-01-28
          • 2019-02-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多