有几个类通常是由其他类派生的。它们是用户输入的接收器,例如按键接收器,键释放接收器,鼠标移动接收器等。从这些类继承的类有:例如,热键操作(它从按键按下接收器和键释放接收器继承),或照相机旋转器(从鼠标移动接收器继承)。用户所做的输入将由另一类转发到相应的接收器,因此是任何输入接收器,例如:相机旋转器需要在该转发类中进行注册。转发输入的类总是相同的,永远不会有两个。

当我的类(class)用户创建新的输入接收器时,该类会继承自鼠标移动接收器,鼠标移动接收器需要知道转发类,才能进行注册以接收鼠标输入。因此,鼠标移动接收器构造函数的代码如下所示:

mouseMoveReceiverIF(inputforwarder* ifo)
{
    ifo.registerInputReceiver(this);
}

由于很明显只有一个inputforwarder,因此如果用户必须通过它不仅不那么直观,而且对于创建的每个输入接收器来说,这都是附加的输入。

但是,如果我将inputforwarder设为单例或全局变量,以便输入接收者可以访问它而无需用户在构造函数中传递它,那么我将遇到其他问题:然后用户需要知道在创建任何inputforwarder之前,inputforwarder必须存在。没有什么可以警告他,没有什么可以迫使他首先创建输入转发器。该程序将简单地崩溃,因为输入接收器将尝试向不存在的输入转发器进行注册。这将更加糟糕。

有效和适当的方式是什么样的?以上示例的替代方法是什么?

谢谢!

最佳答案

首先,我会问您是否应该向用户隐藏InputForwarder的实例。调用这些构造函数的用户代码正在配置系统并设置依赖关系-即使这意味着键入一个额外的构造函数参数,代码很可能应该明确声明那些依赖关系。

假设您要隐藏它,这取决于如何创建输入转发器:

  • 如果可以不使用参数创建它,则使其像一个自启动服务。也就是说,您有一个返回“the”实例的函数,如果在调用该函数时该实例不存在,则该函数将创建它。
  • 如果使用用户提供的参数,则它不能是自动启动的服务。您可以提供一个由用户设置的全局“默认输入转发器实例”,然后在构造函数中检查此实例的存在-如果在该实例中向其注册,否则引发异常。

  • 万一您担心,可测试性在这里可能不是问题。即使您有一个全局“默认”实例来隐藏普通用户的依赖关系,您仍然可以拥有如下构造函数:
    mouseMoveReceiverIF(inputforwarder* ifo = 0)
    {
        if (!ifo) {
            ifo = getDefaultIfo();
            // check for null again if necessary
        }
        ifo.registerInputReceiver(this);
    }
    

    因此,您可以注入(inject)适用于测试的任何inputforwarder。

    关于c++ - 一遍又一遍地传递对象的替代方法,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/15407046/

    10-13 08:20