Al implementar una clase MessageFactory a instatiate Los objetos de mensaje que he usado algo como:registran dinámicamente los métodos constructores en un AbstractFactory en tiempo de compilación usando C++ plantillas
class MessageFactory
{
public:
static Message *create(int type)
{
switch(type) {
case PING_MSG:
return new PingMessage();
case PONG_MSG:
return new PongMessage();
....
}
}
Esto funciona bien, pero cada vez que añada un nuevo mensaje que tengo para agregar un nuevo XXX_MSG y modificar la declaración de cambio.
Después de algunas investigaciones, encontré una forma de actualizar dinámicamente el MessageFactory en tiempo de compilación para que pueda agregar tantos mensajes como quiera sin necesidad de modificar el MessageFactory. Esto permite una más limpio y más fácil de mantener el código, ya que no necesito modificar tres lugares diferentes para añadir/quitar clases de mensajes:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
class Message
{
protected:
inline Message() {};
public:
inline virtual ~Message() { }
inline int getMessageType() const { return m_type; }
virtual void say() = 0;
protected:
uint16_t m_type;
};
template<int TYPE, typename IMPL>
class MessageTmpl: public Message
{
enum { _MESSAGE_ID = TYPE };
public:
static Message* Create() { return new IMPL(); }
static const uint16_t MESSAGE_ID; // for registration
protected:
MessageTmpl() { m_type = MESSAGE_ID; } //use parameter to instanciate template
};
typedef Message* (*t_pfFactory)();
class MessageFactory⋅
{
public:
static uint16_t Register(uint16_t msgid, t_pfFactory factoryMethod)
{
printf("Registering constructor for msg id %d\n", msgid);
m_List[msgid] = factoryMethod;
return msgid;
}
static Message *Create(uint16_t msgid)
{
return m_List[msgid]();
}
static t_pfFactory m_List[65536];
};
template <int TYPE, typename IMPL>
const uint16_t MessageTmpl<TYPE, IMPL >::MESSAGE_ID = MessageFactory::Register(
MessageTmpl<TYPE, IMPL >::_MESSAGE_ID, &MessageTmpl<TYPE, IMPL >::Create);
class PingMessage: public MessageTmpl < 10, PingMessage >
{⋅
public:
PingMessage() {}
virtual void say() { printf("Ping\n"); }
};
class PongMessage: public MessageTmpl < 11, PongMessage >
{⋅
public:
PongMessage() {}
virtual void say() { printf("Pong\n"); }
};
t_pfFactory MessageFactory::m_List[65536];
int main(int argc, char **argv)
{
Message *msg1;
Message *msg2;
msg1 = MessageFactory::Create(10);
msg1->say();
msg2 = MessageFactory::Create(11);
msg2->say();
delete msg1;
delete msg2;
return 0;
}
la plantilla aquí ¿La magia mediante el registro en la clase MessageFactory, todas las nuevas clases de mensajes (por ejemplo, PingMessage y PongMessage) esa subclase de MessageTmpl.
Esto funciona muy bien y simplifica el mantenimiento del código, pero todavía tengo algunas preguntas acerca de esta técnica:
Es ésta una técnica/patrón conocido? ¿cual es el nombre? Quiero buscar más información al respecto.
Quiero hacer la matriz para almacenar los nuevos constructores MessageFactory :: m_list [65536] un std :: mapa, pero al hacerlo hace que el programa segfault incluso antes de llegar a main(). Crear una matriz de 65536 elementos es exagerado, pero no he encontrado una forma de hacer de este un contenedor dinámico.
Para todas las clases de mensajes que son subclases de MessageTmpl tengo que implementar el constructor. Si no, no se registrará en MessageFactory.
Por ejemplo comentando el constructor de la PongMessage:
class PongMessage: public MessageTmpl < 11, PongMessage > { public: //PongMessage() {} /* HERE */ virtual void say() { printf("Pong\n"); } };
daría lugar a la clase PongMessage no estar registrado por el MessageFactory y el programa habría segfault en el MessageFactory :: Create (11) línea . La pregunta es
¿por qué la clase no se registrará? Tener que agregar la implementación vacía de los 100+ mensajes que necesito se siente ineficaz e innecesaria.
# 1 es CRTP (tipo de) http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern – Anycorn
# 3, ya que el constructor de MessageTmpl está protegido (tal vez) – Anycorn
dicho sea de paso, consulte los horarios de código. se ha extraviado; y. caracteres. Lo compilé, sin embargo, tengo un error de segmentación al ejecutarlo. – Anycorn