C++ C++;调用不同的类构造函数,避免切换
我正在程序中捕获一个网络数据包作为C++ C++;调用不同的类构造函数,避免切换,c++,constructor,switch-statement,C++,Constructor,Switch Statement,我正在程序中捕获一个网络数据包作为char*数组。数组的第一个字节表示我收到的数据包的类型,对于每种类型,我希望有一个通用数据包基类的单独子类,我将字节数组传递到该基类,并在其中解释它 我希望避免使用switch语句来计算数据包的第一个字节并调用相应的构造函数。首先是因为在OOP中,您应该避免switch子句,其次是因为我不想在每次添加packet类时向switch语句添加单独的大小写 我研究了工厂方法模式,但我不确定这在这种情况下对我有什么帮助,或者它是否能解决我的问题 基本上,我想要避免的是
char*
数组。数组的第一个字节表示我收到的数据包的类型,对于每种类型,我希望有一个通用数据包基类的单独子类,我将字节数组传递到该基类,并在其中解释它
我希望避免使用switch语句来计算数据包的第一个字节并调用相应的构造函数。首先是因为在OOP中,您应该避免switch子句,其次是因为我不想在每次添加packet类时向switch语句添加单独的大小写
我研究了工厂方法模式,但我不确定这在这种情况下对我有什么帮助,或者它是否能解决我的问题
基本上,我想要避免的是在10个不同的地方编辑代码,只是为了添加一个包类
“我希望避免使用switch语句…”
在某个时候,您需要区分这个字节,无论您是在工厂还是在其他地方这样做
避免切换的一种方法是创建create_class
函数的映射,并根据映射键(区分字节值)查找和调用这些函数
此解决方案的优点是,您可以轻松添加更多的键和创建类函数,而无需更改基本的工厂代码。是的,工厂模式将封装对象创建,您只需将要创建的对象类型传递给它(通过字符串/枚举等)factory模式与普通switch语句相比的一个主要优点是,它将对象创建定位在一个位置。如果数据包类型始终正好是一个字节,则可以创建简单的查找表,如下所示:
struct Packet { virtual ~Packet() {} /* ... */ }; // and abstract
std::map<char, std::unique_ptr<Packet>(*)(char const *, std::size_t)> factory;
std::map<char, std::size_t> packet_size;
实施:
void handle_input(char const * buf, std::size_t available_size)
{
if (available_size == 0) { return; } // no data
if (packet_size[buf[0]] > available_size) { return } // not enough data
auto p = factory[buf[0]](buf, available_size); // create packet
// process p
// reduce available size by packet_size[buf[0]]
}
struct Type05Packet : Packet
{
static std::unique_ptr<Packet> make(char const * buf, std::size_t len)
{
return std::make_unique<Type05Packet>(buf, len);
}
private:
Type05Packet(char const * buf, std::size_t len) { /* populate */ }
};
注意:有几个细节需要改进
- 数据包创建函数应首先尝试解析数据,并且仅在数据有效时调用构造函数,否则它应返回错误条件(例如,nullptr)
- 工厂和大小映射可以在某种自注册全局构造函数中填充。为了保持一致性,它们也可以组合成一个单一的成对值映射
- 地图查找应使用
find(buf[0])
来满足无法识别的数据包类型
- 示例用法可能不太现实。您应该处于某种情况下,您可以自行决定从缓冲区中弹出数据;关键是,只有当有足够的数据形成一个完整的数据包时,您才能这样做
考虑使用跳转表。分配一个函数指针数组,通过您可以键入的消息类型索引,然后在消息处理程序中索引该数组并调用所需函数。工厂模式不会避免切换,而是封装切换,它只会发生一次!您在运行时确定类型,因此必须使用运行时构造,如if-else梯形图的开关。不要太执着于“在OOP中,你应该避免使用switch子句”这样的短语。我认为最优雅的解决方案是有一个函数指针的映射,指向工厂函数。每个子类型一个,键是从char数组读取的字节值。
factory[5] = &Type05Packet::make; // creation function for packet '5'
packet_size[5] = 20; // packet '5' is 20 bytes long