使用模板和继承设计测试

Design test with templates and inheritance

本文关键字:测试 继承      更新时间:2023-10-16

我有一个关于c++设计的问题。正如您在下面的代码中看到的那样,存在一个设计问题。我希望能够有一个TestClass,它继承自零或多个从ModeBase派生的类(ModeOneModeTwo在这个例子中)。如果TestClass继承自ModeOne,它将有能力使用MethodeOne(),这将是TestClass实现MethodOne()的要求,这是我想要的。

class ModeBase
{
//--Methods--------------------------------------------------------------------
public:
    virtual ~ModeBase() = default;
};
class ModeOne : private ModeBase
{
//--Methods--------------------------------------------------------------------
public:
    virtual ~ModeOne() = default;
    virtual void MethodOne() {}
};
class ModeTwo : private ModeBase
{
//--Methods--------------------------------------------------------------------
public:
    virtual ~ModeTwo() = default;
    virtual void MethodTwo() {}
};

class TestBase
{
//--Methods--------------------------------------------------------------------
public:
    TestBase() : currentMode_( nullptr ) {}
    virtual ~TestBase() = default;
    template <class Mode, class T>
    void ChangeMode()
    {
        if( std::is_base_of<Mode, T>::value )
        {
            // Class does inherit from Mode so we make sure the current mode
            // has changed
            currentMode_ = std::make_shared<Mode>();
        }
        else
        {
            // Class does not inherit from Mode so we don't do anything
        }
    }
    template <class Mode>
    bool CurrentMode()
    {
        if( std::dynamic_pointer_cast<Mode>(currentMode_) != nullptr )
        {
            return true;
        }
        return false;
    }
//--Data members---------------------------------------------------------------
private:
    std::shared_ptr<ModeBase> currentMode_;
};
class TestOne
    : public TestBase
    , private ModeOne
    , private ModeTwo
{
//--Methods--------------------------------------------------------------------
    ~TestOne() = default;
    void HeartbeatTick()
    {
        if( CurrentMode<ModeOne>() )
        {
            MethodOne();
        }
        else if( CurrentMode<ModeTwo>() )
        {
            MethodTwo();
        }
    }
    virtual void MethodOne() {}
    virtual void MethodTwo() {}
};

class SomeManager
{
    ~SomeManager() = default;
    void ChangeAllMode()
    {
        for( auto it = vector_.begin(); it != vector_.end(); ++it )
        {
            // Here is the problem with this implementation. I need to know
            // the type of the TestBase derived class (TestOne) to use it as
            // a `ChangeMode` method template parameter.
            //(*it)->ChangeMode<AIModeFollowLine, SOMETYPE>();
        }
    };
    std::vector<std::shared_ptr<TestBase>> vector_;
};

我已经知道这是糟糕的设计,因为vector_将在运行时填充,所以我没有办法使用ChangeMode这样。看来,这将是一个很好的解决方案,使用多种方法,不是吗?如果是这样,设计会是什么样子呢?

Multimethods(又名多重分派)处理基于所涉及的参数的运行时类型分派对单个函数的调用的问题。这似乎不是你的问题(或者我误解了你吗?),因为你有两个不同的方法名称,在两个不同的类型上实现。

您的目标似乎是基于您注入到类中的运行时类型来选择方法实现。目前还不清楚你是否能够决定注入的形式,但如果你是,那么你为什么不直接注入实现?然后可以使用隐式接口而不是显式接口。换句话说,为什么不注入一个类似functor的对象?

class TestBase
{
public:
    typedef std::function<void ()> Ticker;
    TestBase(Ticker hbTicker) : ticker{hbTicker} {}
    void HeartbeatTick() {
       ticker();
    }
    void setTicker(Ticker hbTicker){
        ticker = hbTicker;
    }
private:
    Ticker ticker;
};

如果符合你的要求,我觉得好像没那么复杂。

如果你真的需要实现多重调度,你可能需要在每个需要确定运行时类型的参数上实现visitor模式。不确定这是否适用于多个参数(至少我自己没有尝试过多个参数)。或者您可以使用RTTI和case语句或类似的东西

我真是太蠢了!我只需要使用不同的ChangeMode()方法来了解TestBaseTestOne是否属于ModeBase类型:

template<typename Mode>
bool
IsSame( TestBase* base )
{
     return dynamic_cast<Mode*>(base) != nullptr;
};
template <class Mode>
void
ChangeMode()
{
    if( isSame<Mode>(this) )
    {
        // Change the ticker method
    }
    else
    {
    }
}