代码之家  ›  专栏  ›  技术社区  ›  recipriversexclusion

哪个更好:函数重写或传递用于事件处理的函数指针

  •  4
  • recipriversexclusion  · 技术社区  · 15 年前

    所以,我正在为一个类编写代码,这个类将进入其他人将使用的库中。此类将截获和处理传入消息(详细信息不重要,但它使用的是ActiveMQ CPP库)。这个消费类的大纲是

    class MessageConsumer {
        ...
        public:
            void runConsumer();
            virtual void onMessage(const Message* message);
    }
    

    哪里 runConsumer() 设置连接并开始侦听 onMessage() 在收到消息时调用。

    我的问题是:使用这段代码的人都有自己处理不同消息的方式。我怎么能保持 MessageConsumer 通用,但提供了这种灵活性,同时保持代码简单?

    两种选择:

    • 他们应该从继承一个新类吗 消息消费者 写自己的 OnMessage()。 ?
    • 是否应将指向消息处理函数的指针传递给 消息消费者 ?

    你觉得怎么样,哪个选项更好,为什么?

    谢谢!

    4 回复  |  直到 15 年前
        1
  •  6
  •   Chubsdad    15 年前

    在一种方法中,允许客户端注册回调,然后messageconsumer调用注册的回调。这类似于观察者/广播设计模式。

    第二种方法是策略设计模式,客户机必须继承和重写messageconsumer。

    基本设计目标建议使用最弱的关系来促进松耦合。因为与简单的关联相比,内在性是一个更强大的关系,所以所有其他的方法都是相同的1是首选的。

    Herb's article

    “继承经常被过度使用,甚至 由经验丰富的开发人员提供。总是 最小化耦合:如果一个类 关系可以用更多的 不止一种方法,使用最薄弱的 关系很实际。鉴于 遗产几乎是 你能表达的最强烈的关系 在C++中(仅次于友谊) 只有在 没有同等较弱的 备选方案。”

    但正如詹姆斯指出的,除非清楚地知道总体设计限制,否则很难对其进行评论。

        2
  •  1
  •   chrisaycock spacemanspiff    15 年前

    继承将使您的库更加面向对象,并可能提高可读性。但实际上,选择是相同的,因为编译器将检查用户是否提供了函数(假设您在基类中声明了纯虚拟处理程序),并且底层机制将通过指针(继承情况下的虚拟表)来完成。

        3
  •  1
  •   Tony Delroy    15 年前

    纯虚拟函数允许编译器检查客户端代码是否实现了处理程序。在构造对象之后,虚拟调度立即处于活动状态,并且查看派生类的人可以准确地解释其处理。处理所需的数据可以方便而清晰地分组到派生类中。工厂仍然可以选择要实例化的特定派生类。

    函数指针是运行时状态,因此需要更加小心地及时初始化它们,以便对它们的设置和错误处理进行可选的运行时检查,并解释在程序执行期间哪个集有效。因此,在物体的生命周期内,有更多的自由来改变它们。

    第三种选择是模板策略类,或者奇怪的循环模板模式,在编译时锁定行为。这可能允许回调、死代码消除和其他优化的内联。

        4
  •  0
  •   Basilevs    15 年前

    虚函数或逐级函数是实现的方法。这些方法比函数指针方法提供更大的灵活性和更松散的耦合。

    为了说明-函数指针方法可以和前两个方法包装在一起,但不能与前两个方法包装在一起。

    void cbFunction();
    
    class Interface {
      virtual void act() =0 ;
    };
    
    class CbFuctionWrapper:public Interface {
    public:
      virtual void act() {cbFunction()};
    };
    
    class AnotherImpl: public Interface {
      Context _c; // You can't pass additional context with usual function without downcasting, but OO is all about that.
    public:
      virtual void act() {...}
    }