优点 &回调(std::function/std::bind)与接口(抽象类)的缺点 [英] Pros & cons of a callback (std::function/std::bind) vs an interface (abstract class)

查看:44
本文介绍了优点 &回调(std::function/std::bind)与接口(抽象类)的缺点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 Boost.Asio 在 C++11 中创建服务器应用程序.我创建了一个类,Server,它负责接受新的连接.基本上就是:

I'm creating a server application in C++11 using Boost.Asio. I've created a class, Server, which takes care of accepting new connections. It's basically just:

void Server::Accept() {
  socket_.reset(new boost::asio::ip::tcp::socket(*io_service_));
  acceptor_.async_accept(*socket_,
                         boost::bind(&Server::HandleAccept, this, boost::asio::placeholders::error));
}

void Server::HandleAccept(const boost::system::error_code& error) {
  if (!error) {
    // TODO
  } else {
    TRACE_ERROR("Server::HandleAccept: Error!");
  }
  Accept();
}

我找到了两种方法(我确定还有更多)来修复"TODO 注释,即将套接字移动到它应该去的地方.在我的例子中,我只希望它回到拥有 Server 实例的类实例(然后将它包装在一个 Connection 类中并将其插入到一个列表中).>

I've found two ways (I'm sure there are more) to "fix" the TODO comment, i.e. to move the socket to wherever it should go. In my case I just want it back to the class instance that owns the Server instance (which then wraps it in a Connection class and inserts it to a list).

  1. Server 在其构造函数中有一个参数:std::functionHandleAccept 中调用的 OnAccept.
  2. 我创建了一个抽象类,IServerHandler 或其他类,它有一个虚拟方法 OnAccept.ServerIServerHandler 作为其构造函数中的参数,拥有服务器实例的类实例扩展了 IServerHandler 并构造了 Server*this 作为参数.
  1. Server has a parameter in its constructor: std::function<void(socket)> OnAccept which is called in HandleAccept.
  2. I create an abstract class, IServerHandler or whatever, which has one virtual method OnAccept. Server takes IServerHandler as parameter in its constructor and the class instance owning the server instance extends IServerHandler and constructs Server with *this as parameter.

选项 1 与选项 2 的优缺点是什么?有没有更好的选择?我在 Connection 类 (OnConnectionClosed) 中遇到了同样的问题.此外,根据我决定如何设计系统,它可能需要一个 OnPacketReceivedOnPacketSent 回调.

What are the pros and cons of option 1 vs option 2? Are there any better options? I'm having the same problem in my Connection class (OnConnectionClosed). Also, depending on how I decide to design the system, it might need a OnPacketReceived and OnPacketSent callback.

推荐答案

我非常喜欢第一种方式,原因有几个:

I strongly prefer the first way for several reasons:

  • 通过接口/类层次结构表示概念/功能会使代码库的通用性和灵活性降低,并且在未来更难维护或扩展.这种设计对类型(实现所需功能的类型)强加了一组要求,这使得将来难以修改,并且在系统更改时最容易失败(考虑在修改基类时会发生什么)这种类型的设计).

  • Representing concepts/functionality via interfaces/class hierarchies makes the code base less generic, flexible, and then more difficult to mantain or scale in the future. That kind of design imposes a set of requirements on the type (the type implementing the required functionality) which makes it difficult to modify in the future, and most prone to fail when the system changes (Consider what happens when the base class is modified in this type of designs).

你所说的回调方法只是鸭子输入的经典例子.服务器类只期望实现所需功能的可调用事物,仅此而已.不需要你的类型必须与这个层次结构耦合"条件,所以实现处理的类型是完全自由的.

What you called the callback approach is just the classic example of duck typing. The server class only expects a callable thing which implements the required functionality, nothing more, nothing less. No "your type must be coupled to this hierarchy" condition is required, so the type which implements handling is completely free.

此外,正如我所说,服务器只需要一个可调用的东西:它可以是任何具有预期函数签名的东西.这在实现处理程序时为用户提供了更多的自由.可以是全局函数、绑定成员函数、函子等.

Also, as I said the server only expects a callable thing: It could be anything with the expected function signature. This gives the user more freedom when implementing a handler. Could be a global function, a bound member function, a functor, etc.

以标准库为例:

  • 几乎所有标准库算法都基于迭代器范围.C++中没有iterator接口.迭代器只是实现迭代器行为的任何类型(可取消引用、可比较等).迭代器类型是完全自由的、独特的和解耦的(未锁定到给定的类层次结构).

  • Almost all standard library algorithms are based on iterator ranges. There is no iterator interface in C++. An iterator is just any type which implements the behaviour of an iterator (Being dereferenceable, comparable, etc). Iterator types are completely free, distinct, and decoupled (Not locked to a given class hierarchy).

另一个例子可能是比较器:什么是比较器?只是带有布尔比较函数签名的任何东西,可调用的东西,它接受两个参数并返回一个布尔值,说明两个输入值是否从该点开始相等(小于、大于等)来看一个具体的比较标准.没有Comparable接口.

Another example could be comparators: Whats a comparator? Is just anything with the signature of a boolean comparison function, something callable which takes two parameters and returns a boolean value saying if the two input values are equal (less than, bigger than, etc) from the point of view of a specific comparison criteria. There is no Comparable interface.

这篇关于优点 &amp;回调(std::function/std::bind)与接口(抽象类)的缺点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆