Design Pattern: Singleton

por Fabio A. Mazzarino

Design Patterns, ou Padrões de Projeto, são soluções gerais para problemas comuns de desenvolvimento de software, apesar de controversas são considerados um conjunto de melhores práticas. Um desses padrões é o Singleton, utilizado para garantir que somente haverá uma instância dessa classe no programa todo, sem impactar na facilidade de acesso a essa instância.

Singleton Template

Uma abordagem para criação de um singleton é a criação de uma classe template, que gerencia a instanciação da classe:


#include <iostream>
#include <string>

template <class T>
class Singleton {
private:
    static T* instance;

public:
    static T& getInstance() {
        if (!instance)
            instance = new T();
        return *instance;
    }
};

template <class T>
T* Singleton<T>::instance = NULL;


class Config {
private:
    Config() {
        std::cout << "New Config instance" << std::endl;
    }
    friend class Singleton<Config>;

public:
    bool parse(std::string filename) {
        return true;
    }
    std::string getValue(std::string key) {
        return "";
    }
};


int main() {
    Config config = Singleton<Config>::getInstance();
    Config conf = Singleton<Config>::getInstance();
}

A saída para o código acima:

New Config instance

Note a classe Singleton, bem simples, usando template, e o método getInstance. A class Config precisa de duas coisas: primeiro precisa ter um construtor privado evitando ser instanciado com new; segundo precisa declarar a classe Singleton como friend para que somente a Singleton possa acessar seu construtor.

A partir daí sempre que for chamado Singleton<Config>::getInstance() haverá uma única instanciação da classe Config, e nenhuma mais.

Um cuidado com a classe declarada acima é a concorrência, como Singleton::getInstance() não é atômico, pode ocorrer de duas threads distintas solicitem uma instância simultaneamente, o que pode causar uma racing condition, e duas instâncias da classe ser criada. Isso pode ser resolvido com um mutex.

Desvantagens do Singleton

Como a implementação depende de uma classe estática, haverá alguns problemas no desenvolvimento de mocks para testes unitários, dificultando TDD.

Além disso existe o criticismo dos Design Patterns, diz que os Design Patterns apesar de parecerem uma ótima ideia podem trazer mais problemas que soluções a partir do momento em que o esforço para se manter dentro dos padrões acaba por dificultar o desenvolvimento ou a manutenção do código. Mas é uma discussão muito maior que um Snippets para Singleton.