C ++ Quale dei seguenti è un migliore approccio al modello singleton?

-2

Ora sono bloccato nel server che sto programmando, semplicemente perché non riesco a trovare un modo valido e affidabile per gestire le mie classi "oggetto singolo", ho tentato il pattern Singleton ma è semplicemente brutto dover digitare tutto più e più volte.

Ho questa classe "TConnectionManager" che in pratica gestisce tutto il codice relativo alla connessione alle connessioni attive sul mio server.

Pattern Singleton - connections.h

Singleton destructor would delete all connections left in "Connections" variable

class TConnectionManager
{
public:
    std::list<TConnection*> Connections;
private:
    std::mutex ConnectionsLock;
public:
    static TConnectionManager& getInstance()
    {
        static TConnectionManager instance;
        return instance;
    }

    TConnectionManager() = default;
    ~TConnectionManager();

    // non-copyable
    TConnectionManager(const TConnectionManager&) = delete;
    TConnectionManager& operator=(const TConnectionManager&) = delete;

    TConnection* CreateConnection(boost::asio::io_service& IOService);
    void ReleaseConnection(TConnection* Connection);
    void ProcessConnections();
};

Per me dover digitare "getInstance" più e più volte diventa frustrante così com'è, così ho provato a cercare in molti posti e non sono riuscito a trovare una soluzione migliore, e ci sono anche molti punti di vista diversi.

Ho tentato di farlo, il che sembra molto più pulito:

C Like - connections.h

Without a real destructor, I'd have to call the "ExitConnections" method at the end of the program to delete all remaining active connections, or set the std::atexit method

extern std::list<TConnection*> Connections;
extern std::mutex ConnectionsLock;

TConnection* CreateConnection(boost::asio::io_service& IOService);
void ReleaseConnection(TConnection* Connection);
void ProcessConnections();
void ExitConnections(); // Destructor alike function which deletes all connections

Ho anche provato ad avere uno "spazio dei nomi" di classe statica

Metodi statici e variabili (spazio dei nomi) - connections.h

Same approach as for the C-Like methods and variables, use ExitConnections method act as a destructor to delete all remaining active connections

class TConnectionManager
{
public:
    static std::list<TConnection*> Connections;
private:
    static std::mutex ConnectionsLock;
public:
    static TConnection* CreateConnection(boost::asio::io_service& IOService);
    static void ReleaseConnection(TConnection* Connection);
    static void ProcessConnections();
    static void ExitConnections();
};

Quindi non so quale dei tre modi in seguito menzionati sia l'approccio migliore per gestire questa situazione in cui sono bloccato.

    
posta Raúl Sanpedro 11.08.2016 - 20:52
fonte

2 risposte

-1

Mantieni il pattern singleton contenuto in un solido design solido senza spargere i dettagli al mondo esterno.

Per digitare a corto circuito per il tuo caso d'uso particolare, crea semplicemente le funzioni wrapper (con nomi brevi quanto vuoi) e inseriscile in un namespace.

/* TConnectionManagerWrpr.h file */
#include "TConnectionManager.h"
namespace TConnectionManagerWrpr {
   TConnectionManager geC();
   TConnection* CreateC(boost::asio::io_service& IOService);
   void ReleaseC(TConnection* Connection);
   void ProcessC();
   void ExitC(); 
}

Nel tuo codice, puoi chiamarli come:

#include "TConnectionManagerWrpr.h"
using namespace TConnectionManagerWrpr;

void f() {
    TConnection* tc=CreateC(...);
    ReleaseC(tc);
    ExitC(tc);
}
    
risposta data 12.08.2016 - 00:46
fonte
-1

Puoi ancora utilizzare le singole istanze di oggetti.

Questi oggetti separati saranno solo wrapper di peso leggero dell'istanza singleton. È anche un modello Pimpl (puntatore all'implementazione) , tranne per il fatto che questo wrapper non ha nemmeno "il proprio" l'oggetto di implementazione.

Nota che non sto sostenendo questa risposta per nessun altro approccio. Per uno, questo approccio richiede la duplicazione della dichiarazione di ogni metodo, che è uno svantaggio che è comunemente associato al schema di decorazione e < a href="https://en.wikipedia.org/wiki/Delegation_(object-oriented_programming)"> delega . Spetta a te decidere se il vantaggio superi l'inconveniente.

Nota 2. È possibile inserire i metodi statico e di istanza nella stessa classe, rinominando ciascun metodo statico (ad esempio, aggiungere un prefisso "Statico" prima di ogni metodo).

Nota 3. Ricordo che mi è stato detto da un programmatore anziano che getInstance() è una buona cosa, perché trasmette il fatto che tutte le azioni su questa classe saranno gestite da un'istanza singleton; la palese ovvietà di questa dicitura (tipizzazione extra) aiuta a evitare errori di programmazione.

#include "TConMan.h"

class Wrapper
{
public:
    Wrapper() : m_impl(TConMan::getInstance()) {}
    ~Wrapper() {} // do nothing; real cleanup happens on TConMan

public:
    // For each method on TConMan, 
    // implement a method of same name, signature, and return values.
    // Inside each method, forward the call to the actual method 
    // on "m_impl".

private:
    // non-copyable member declarations here. 

private:
    TConMan& m_impl;
};
    
risposta data 11.09.2016 - 10:22
fonte

Leggi altre domande sui tag