Graphics Programming
템플릿을 이용해 팩토리 함수에서 switch-case 없애기 본문
베이스가 되는 Packet 클래스가 있고, 이를 상속한 PacketA, PacketB, PacketC 클래스가 있다. 그리고 각 패킷 클래스에 대응하는 enum이 있다.
// packet.h
enum class PacketType : uint16_t {
PACKET_A = 0,
PACKET_B = 1,
PACKET_C = 2,
NUM_PACKETS = 3
}
struct Packet {
Packet(PacketType type);
PacketType type;
};
struct PacketA : Packet {
PacketA();
};
struct PacketB : Packet {
PacketB();
};
struct PacketC : Packet {
PacketC();
};
// packet.cpp
Packet::Packet(PacketType type_) : type(type_) {}
PacketA::PacketA() : Packet(PacketType::PACKET_A) {}
PacketB::PacketB() : Packet(PacketType::PACKET_B) {}
PacketC::PacketC() : Packet(PacketType::PACKET_C) {}
이제 PacketType을 가지고 대응하는 패킷 인스턴스를 생성하는 팩토리 함수를 만들려고 한다. 가장 단순한 방법은 switch-case이다.
Packet* fromPacketFactory(PacketType type) {
switch(type) {
case PacketType::PACKET_A:
return new PacketA;
case PacketType::PACKET_B:
return new PacketB;
case PacketType::PACKET_C:
return new PacketC;
}
return nullptr;
}
실행 속도는 빠를 지 몰라도 패킷 종류가 많아질 수록 타이핑이 귀찮아진다. 템플릿을 이용해서 팩토리 함수를 간단하게 만들어보자.
// packet.h
// ... 위와 동일
extern std::function<void*()> packetFactory[static_cast<uint16_t>(PacketType::NUM_PACKET_TYPES)];
template<typename T>
struct __factory_initializer {
__factory_initializer(PacketType typeEnum) {
auto generator = []() -> void* { return new T; };
uint16_t ix = static_cast<uint16_t>(typeEnum);
assert(packetFactory[ix] == nullptr);
packetFactory[ix] = generator;
}
};
#define REGISTER_PACKET(TypeEnum, PacketClass) \
__factory_initializer<PacketClass> __factory_initializer_##PacketClass(TypeEnum);
// packet.cpp
std::function<void*()> packetFactory[static_cast<uint16_t>(PacketType::NUM_PACKET_TYPES)] = { nullptr, };
Packet::Packet(PacketType type_) : type(type_) {}
REGISTER_PACKET(PacketType::PACKET_A, PacketA)
PacketA::PacketA() : Packet(PacketType::PACKET_A) {}
REGISTER_PACKET(PacketType::PACKET_B, PacketB)
PacketB::PacketB() : Packet(PacketType::PACKET_B) {}
REGISTER_PACKET(PacketType::PACKET_C, PacketC)
PacketC::PacketC() : Packet(PacketType::PACKET_C) {}
이러면 팩토리 함수에서 switch-case를 없앨 수 있다.
Packet* fromPacketFactory(PacketType type) {
auto generator = packetFactory[static_cast<uint16_t>(type)];
assert(generator != nullptr);
Packet* packet = reinterpret_cast<Packet*>(generator());
return packet;
}