c++ - 根据抽象类快速确定子类

标签 c++ inheritance design-patterns

我有一个 C++ 基类 CAbstrInstruction 和大量的直接子类:

class CAbstrInstruction { /* ... */ };

class CSleepInstruction: public CAbstrInstruction { /* ... */ };
class CSetInstruction: public CAbstrInstruction { /* ... */ };
class CIfInstruction: public CAbstrInstruction { /* ... */ };
class CWhileInstruction: public CAbstrInstruction { /* ... */ };
// ...

还有一个 CScriptWorker 公开了一个公共(public)方法 execute:

class CScriptWorker
{
    public:
        void execute (const CAbstrInstruction *pI);

    private:
        void doSleep (const CSleepInstruction *pI);
        void doSet (const CSetInstruction *pI);
        void doIf (const CIfInstruction *pI);
        void doWhile (const CWhileInstruction *pI);
        // ...
};

execute 方法的实现目前看起来是这样的:

void CScriptWorker::execute (const CAbstrInstruction *pI)
{
    const CSleepInstruction *pSleep =
        dynamic_cast<const CSleepInstruction *>(pI);

    if (pSleep != NULL)
    {
        doSleep (*pSleep);
        return;
    }

    const CSetInstruction *pSet =
        dynamic_cast<const CSetInstruction *>(pI);

    if (pSet != NULL)
    {
        doSet (*pSet);
        return;
    }

    const CIfInstruction *pIf =
        dynamic_cast<const CIfInstruction *>(pI);

    if (pIf != NULL)
    {
        doIf (*pIf);
        return;
    }

    const CWhileInstruction *pWhile =
        dynamic_cast<const CWhileInstruction *>(pI);

    if (pWhile != NULL)
    {
        doWhile (*pWhile);
        return;
    }

    /* ... */
}

这非常笨拙,需要 O(log(n)) 才能调用正确的私有(private)方法。有没有 有什么设计模式或语言结构可以简化这个吗?

澄清:我可以将私有(private)执行方法do...移动到指令中 类。 execute 方法将简单地变为:

    void execute (const CAbstrInstruction *pI) { pI->execute(); }

然而,这不是我想要的。为什么不? 关注点分离:CAbstrInstruction 的实例只是描述要做什么。它们构成了脚本的抽象语法树。已经足够关心了。 CScriptWorker 关心的是实际执行指令所描述的操作。 CScriptWorker 知道脚本运行的上下文。CAbstrInstruction 不应该知道。

最佳答案

如果事情很简单,将execute 方法的实现移动到CAbstrInstruction 的子类中可能就是答案。然而,OP 明确指出 execute 方法应该在 CScriptWorker 中保持独立,以分离了解什么要完成的问题(指令的工作)从如何完成(CScriptWorker 的工作)。这可以通过双重调度来实现,有时也称为访问者模式:

class IInstructionDispatchTarget
{
    public:
    virtual void onDispatch (const CSleepInstruction &instr) = 0;
    virtual void onDispatch (const CSetInstruction &instr) = 0;
};
class CAbstrInstruction
{
    public:
    virtual void dispatch (IInstructionDispatchTarget &t) const = 0;
};
class CSleepInstruction: public CAbstrInstruction
{
     public:
     virtual void dispatch (IInstructionDispatchTarget &t) const override
         { t.onDispatch (*this); }
};
class CSetInstruction: public CAbstrInstruction
{
     public:
     virtual void dispatch (IInstructionDispatchTarget &t) const override
         { t.onDispatch (*this); }
};
class CScriptWorker: public IInstructionDispatchTarget
{
    public:
    void execute (const CAbstrInstruction *pI)
        { pI->dispatch (*this); }
    virtual void onDispatch (const CSleepInstruction &instr) override
    {
        // do sleep
    }
    virtual void onDispatch (const CSetInstruction &instr) override
    {
        // do set
    }
};

executeCScriptWorker 上被调用时,它会调用指令的 dispatch 方法。作为返回,该指令使用其特定的 this 指针调用分派(dispatch)目标上的 onDispatch 方法,从而调用正确的方法。

IInstructionDispatchTarget 接口(interface)有两个用途。一方面,它确保 CAbstrInstruction 的实例根本不需要知道 CScriptWorker;他们需要知道的只是界面。另一方面,它允许其他调度目标使用相同的机制,例如在遍历优化 AST 的指令时。

如果 IInstructionDispatchTarget 的存在被认为是不必要的,事情可以稍微简化,如 ROX 的答案所示。

关于c++ - 根据抽象类快速确定子类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50983868/

相关文章:

c++ - '虚拟 xyz' 与 'xyz virtual' 方法

C++ 使用继承为对象分配空间

java - 在 Spring bean 中实现空对象设计模式

c# - 工作单元类如何知道在提交时调用哪个存储库?

c++ - 在 C++ 中标记 "Braced Initializer List"样式的字符串(使用 Boost?)

c++ - 使用自定义特征和 bool 类型的 c++11 枚举时出现 clang 编译错误

python - 访问父类(super class)属性

java - 套接字连接的单例类不起作用

c++ - 如何打印元组 vector ?

c++ - 为基类和派生类实现 MFC 序列化