Back-End

8 dez, 2011

Singleton – garantindo a unicidade de objetos

Publicidade

Para aqueles que nunca ouviram o termo “Design Patterns”, segue a explicação da mãe Wikipedia:

Os padrões de projeto de software ou padrões de desenho de software, também muito conhecidos pelo termo original em inglês, Design Patterns, descrevem soluções para problemas recorrentes no desenvolvimento de sistemas de software orientados a objetos.

Um padrão de projeto estabelece um nome e define o problema, a solução, quando aplicar esta solução e suas consequências. Os padrões de projeto visam facilitar a reutilização de soluções de desenho – isto é, soluções na fase de projeto do software, sem considerar reutilização de código. 

Também acarretam um vocabulário comum de desenho, facilitando comunicação, documentação e aprendizado dos sistemas de software.

Agora conhecendo o significado do termo design patterns, iniciaremos os estudos com um pattern chamado Singleton. O Singleton é um modelo voltado para garantir a unicidade da instância, ou seja, impede que exista mais de uma instância do mesmo objeto.

Para melhor compreensão vou citar aqui um exemplo adaptado do livro Zend Framework – Componentes Poderosos para PHP de Flávio Gomes Lisboa: imagine um castelo medieval, cercado por um lago profundo povoado de ferozes crocodilos, onde a única forma de se adentrar seria atravessando uma ponte levadiça, que estaria sendo manipulada por um guarda real.

Transferindo essa situação à programação, encontramos a figura castelo representada por sua aplicação em si. Já o guarda real e a ponte seriam um objeto controlador, responsável pela verificação e gerência de acesso das requisições enviadas pelo usuário e ações internas. Por fim, a tarefa de garantir a unicidade da entrada do castelo estaria com o padrão singleton, que forçaria sempre a utilização da mesma instância do objeto. Apenas para questões de curiosidade, o termo singleton vem do inglês e significa: situação quando resta-se apenas uma carta nas mãos, num jogo de baralho.

Exemplificação realizada, dada a hora de analisar como trabalha o Singleton!

Gostaria de dizer que esta primeira versão de código singleton que irei disponibilizar está incorreta, pois possui erros graves. Você pode-se perguntar nesse momento: e por que mencioná-la então? Porque infelizmente encontrei dezenas de tutoriais na internet utilizando dessa versão incorreta do código para definir um singleton. Antes mesmo de apresentar a versão incorreta, e sendo bastante repetitivo, devo lembrá-los novamente que o propósito singleton (single = único) é garantir, de todas as maneiras possíveis, a única instância do objeto. Ou seja – se de alguma forma um objeto possui duas instâncias, ele não utiliza o padrão singleton, ao menos que o propósito desse objeto seja composto – em outras palavras, fazendo uso de mais de um padrão de projeto.

Compreendido o propósito singleton, vamos à versão incorreta:

[php]
class singleton
{
private static $_instance = null;

public static function getInstance()
{
if(self::$_instance == null){
self::$_instance = new singleton();
}
return self::$_instance;
}
}
[/php]

Devo ressaltar que para total compreensão deste artigo é indispensável ser familiarizado com a programação orientada a objeto. Dessa forma, caso não conheça o conceito de POO, sugiro o livro – PHP Programando com Orientação a Objetos de Pablo Dall’Oglio, ou pelo menos uma boa leitura do tema pela internet.

Voltando à versão incorreta do código singleton, podemos facilmente observar que existem três maneiras de instanciar o objeto singleton, são elas:

  • Através do operador new – $singleton = new singleton;
  • Através do método estático getInstance – $singleton = singleton::getInstance();
  • Através do operador/método (muitas vezes esquecido) clone – $singletonClone = clone $singleton.

Utilizando a versão incorreta do código, facilmente todo o propósito singleton é perdido, uma vez que pode-se instanciar esse objeto não apenas uma, nem duas, mas de três maneiras diferentes. Isto é, nesse caso o singleton não é confiável, pois não conseguiria garantir 100% da unicidade do objeto.

Nesse momento, devo citar a bela frase do escritor romano Publilius Syrus: “Observando os erros dos outros, o homem sábio corrige os seus”. Devemos, então, observar as “passagens”  indesejadas em nosso código e “fechá-las”, restando apenas um local de acesso à instância do nosso objeto.

Analisando a estrutura lógica desse padrão de projeto, observamos que o objeto utiliza-se de seu método estático e público getInstance() (pegar instância) para retornar (return) o valor contido no atributo estático e privado (private) $_instance. Apenas fazendo um parênteses, utilizamos cifrão + underline “$_” geralmente para atributos que serão implementados na classe filha, porém por padrão já estabelecido ao singleton, também é aconselhável utilizar. Para finalizar a análise da estrutura lógica do modelo singleton, observamos a ação do condicional if. Nesse passo, antes que o objeto retorne o valor contido no atributo $_instance, o mesmo deve ser submetido ao condicional que verifica se uma instância do objeto foi atribuída a esse atributo, ou seja, se $_instance for diferente de nulo (null), atribui-se a ele uma instância do próprio objeto, e por fim retorna-se o valor do atributo.

Veja agora a versão correta do padrão singleton:

[php]
class singleton
{
private static $_instance = null;

private function __construct(){}

private function __clone(){}

public static function getInstance()
{
if(self::$_instance === null){
self::$_instance = new self;
}
return self::$_instance;
}
}
[/php]