Dynamisches Registrieren von Konstruktormethoden in einer AbstractFactory zur Kompilierungszeit mithilfe von C ++ - Vorlagen

Beim Implementieren einer MessageFactory-Klasse zum Instatisieren von Message-Objekten habe ich Folgendes verwendet:

class MessageFactory 
{
  public:
    static Message *create(int type)
    {
       switch(type) {
         case PING_MSG:
            return new PingMessage();
         case PONG_MSG:
            return new PongMessage();
         ....
    }
}

Dies funktioniert in Ordnung, aber jedes Mal, wenn ich eine neue Nachricht hinzufüge, muss ich eine neue XXX_MSG hinzufügen und die switch-Anweisung ändern.

Nach einiger Recherche habe ich eine Möglichkeit gefunden, die MessageFactory beim Kompilieren dynamisch zu aktualisieren, sodass ich beliebig viele Nachrichten hinzufügen kann, ohne die MessageFactory selbst ändern zu müssen. Dadurch wird der Code übersichtlicher und einfacher zu warten, da ich nicht drei verschiedene Stellen ändern muss, um Nachrichtenklassen hinzuzufügen / zu entfernen:

#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;                                                                                                                                                                                  
} 

Die Vorlage hier führt die Magie aus, indem in der MessageFactory-Klasse alle neuen Nachrichtenklassen (z. B. PingMessage und PongMessage) registriert werden, die von MessageTmpl untergeordnet sind.

Dies funktioniert hervorragend und vereinfacht die Codewartung, aber ich habe noch einige Fragen zu dieser Technik:

Ist dies eine bekannte Technik / ein bekanntes Muster? wie heißt? Ich möchte weitere Informationen dazu suchen.

Ich möchte das Array zum Speichern neuer Konstruktoren machenMessageFactory :: m_List [65536] a std :: map, aber dies führt dazu, dass das Programm bereits vor dem Erreichen von main () einen Segfault ausführt. Das Erstellen eines Arrays mit 65536 Elementen ist überflüssig, aber ich habe keine Möglichkeit gefunden, dies zu einem dynamischen Container zu machen.

Für alle Nachrichtenklassen, die Unterklassen von MessageTmpl sind, muss ich den Konstruktor implementieren. Wenn nicht, wird es nicht in der MessageFactory registriert.

Zum Beispiel den Konstruktor der PongMessage kommentieren:

 class PongMessage: public MessageTmpl < 11, PongMessage >       
 {                                                                                                                                                                                           
   public:                                                                                                                                                                                    
    //PongMessage() {} /* HERE */                                                                                                                                                                          
    virtual void say() { printf("Pong\n"); }                   
 };

would dazu führen, dass die PongMessage-Klasse nicht von der MessageFactory registriert wird und das Programm imMessageFactory :: Create (11) Linie. Die Frage is
Warum wird die Klasse nicht registriert? Die leere Implementierung der über 100 Nachrichten, die ich benötige, hinzufügen zu müssen, fühlt sich ineffizient und unnötig an.

Antworten auf die Frage(14)

Ihre Antwort auf die Frage