我正在我的程序中捕获一个char*
数组的网络数据包。数组的第一个字节表示我收到的数据包的类型,对于每种类型,我希望我的通用Packet
基类的单独子类传递给字节数组以及它将被解释的位置。
我想避免使用switch语句,其中将评估数据包的第一个字节并调用相应的构造函数。首先,因为在OOP中你应该避免使用switch子句,其次是因为每次添加数据包类时我都不想在switch语句中添加单独的case。
我查看了工厂方法模式,但我不确定在这种情况下这对我有什么帮助,或者它是否能解决我的问题。
基本上我想避免的是在10个不同的地方编辑我的代码只是为了添加一个数据包类。
答案 0 :(得分:5)
"我想避免使用switch语句......"
在某些时候,无论您是在工厂还是其他地方进行此操作,您都需要区分此字节。
避免switch
的一种方法是创建create_class
函数的映射,并根据映射键(区分字节值)查找并调用它们。
此解决方案具有以下优势:您可以轻松添加更多密钥和create_class
功能,而无需更改基本工厂代码。
答案 1 :(得分:3)
如果数据包类型总是正好是一个字节,那么您可以创建简单的查找表,如下所示:
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 */ }
};
您必须添加工厂数据(例如在main()
中):
factory[5] = &Type05Packet::make; // creation function for packet '5'
packet_size[5] = 20; // packet '5' is 20 bytes long
注意:您应该改进几个细节。
find(buf[0])
来满足无法识别的数据包类型。答案 2 :(得分:1)
是的工厂模式会封装对象创建,你只需要传递它想要创建的对象类型(通过字符串/枚举等)。工厂模式优于普通switch语句的一个主要优点是它本地化对象创建在一个地方。
答案 3 :(得分:0)
考虑使用跳转表。分配一个函数指针数组,由你可以键入消息类型的东西索引,然后在消息处理程序索引该数组并调用所需的函数。