Introdução
Esse artigo é para ser o primeiro de uma série de artigos que vou escrever para documentar os meus estudos sobre o Design Pattern (Padrões de Projeto) e aproveitar para compartilhar esses estudos com a comunidade em forma de artigos.
Nesta série, vou demonstrar alguns dos principais padrões de projeto do mercado. A minha ideia não é falar de todos os padrões existentes, mas sim explicar alguns dos principais e demonstrar com um exemplo a sua implementação na linguagem PHP.
Design Patterns
Antes de partirmos para o nosso primeiro padrão, como esse é o primeiro artigo dessa série, achei melhor dar um pequena explicação sobre o que são os padrões de projeto de uma forma mais ampla e contar um pouco da sua história.
Para começar, nada melhor do que citar um dos livros de maior referência sobre o assunto; estou falando do “Padrões de Projeto – Soluções Reutilizáveis de Software Orientado a Objetos”, da famosa Gang of Four (Gangue dos Quatro) de 1994, onde os quatro autores “Erich Gamma”, “John Vlissides”, “Ralph Johnson” e “Richard Helm” descrevem 24 design patterns. Eles os separam em três categorias: padrões de criação, padrões estruturais e padrões comportamentais. Nesta série eu vou escolher dois padrões de cada categoria para explicar e demonstrar o seu funcionamento.
Apesar de existirem mais do que os 24 padrões mencionados, este livro, mesmo nos dias atuais – como mencionado anteriormente – é uma das maiores referências sobre o assunto.
Singleton Pattern
Agora podemos começar, e para isso, achei melhor falar sobre o padrão de criação Singleton. Vou explicar a sua estrutura, qual problema ele busca resolver, e mostrar um exemplo de como podemos usar esse padrão nos nossos projetos desenvolvidos com PHP.
Problema a resolver
O padrão Singleton prega a ideia da instância única, onde quando você tenta criar uma instância da sua classe, essa classe deve verificar a existência da instância para que se a instância não existir, criar uma nova, e caso contrário retornar a mesma instância sem criar uma nova, garantindo assim menor consumo de memória e um único ponto de acesso global para esse recurso.
O Singleton tem uma estrutura bem simples e de fácil compreensão, como na imagem abaixo.
Esse é o diagrama UML do padrão Singleton
Esse padrão é bastante usado para o desenvolvimento de classes responsáveis pelo gerenciamento da conexão com o banco de dados ou o gerenciamentos de logs, nos permitindo ter acesso a esses recursos na nossa aplicação de forma rápida e descomplicada.
Implementação normal
Agora finalmente falaremos de código, mas primeiro vamos criar uma classe da forma convencional – uma pequena classe de Logs. Vou usar esse exemplo para demostrar que a cada instância criada estamos literalmente criando uma nova instância na memória.
<?php class Log { } $log = new Log; $log2 = new Log; $log3 = new Log; $log4 = new Log; $log5 = new Log; var_dump($log); var_dump($log2); var_dump($log3); var_dump($log4); var_dump($log5);
Se executarmos o exemplo acima, poderemos ver que a cada nova chamada da classe Log, nós criamos uma nova instância, começando com #1 e indo até #5.
object(Log)#1 (0) { } object(Log)#2 (0) { } object(Log)#3 (0) { } object(Log)#4 (0) { } object(Log)#5 (0) { }
Implementação Singleton
Agora vamos começar a implementar o padrão Singleton na nossa classe. Faremos isso alterando a visibilidade dos nosso métodos mágicos *__construct* o *__wakeup* e do *__clone*.
private function __construct() { } private function __clone() { } private function __wakeup() { }
Com isso, garantimos que a classe não pode ser mais instanciada de forma normal.
Vamos criar uma propriedade privada estática $instance
private static $instance;
E também vamos criar um método estático getInstance que vai ser o único responsável por retornar a nova instância da nossa classe. É neste método que vamos verificar se já existe uma instância na nossa classe.
public static function getInstance() { if(self::$instance === null){ self::$instance = new self; } return self::$instance; }
Se der certo, vamos ter um arquivo como no exemplo abaixo.
<?php class Log { private static $instance; private function __construct() { } private function __clone() { } private function __wakeup() { } public static function getInstance() { if(self::$instance === null){ self::$instance = new self; } return self::$instance; } }
Agora com a nossa classe devidamente modificada, podemos testar o nosso exemplo.
$log = Log::getInstance(); $log2 = Log::getInstance(); $log3 = Log::getInstance(); $log4 = Log::getInstance(); $log5 = Log::getInstance(); var_dump($log); var_dump($log2); var_dump($log3); var_dump($log4); var_dump($log5);
No exemplo acima, agora com o nosso Singleton funcionando, vamos ver que a nossa instância é sempre a mesma #1. Conseguimos garantir a mesma instância, não importa quantas vezes chamamos a nossa classe.
object(Log)#1 (0) { } object(Log)#1 (0) { } object(Log)#1 (0) { } object(Log)#1 (0) { } object(Log)#1 (0) { }
Singleton é um anti pattern?
Para muitos desenvolvedores o, Singleton é considerado um anti patterns, mas por que será? Acredito que uns dos principais motivos é pela natureza estática. Isso nos traz alguns problemas como não podermos trabalhar com interfaces e o aumento de acoplamento na classe. Além disso, como estamos falando de acesso global, existe um perigo de sobrescrever o comportamento da classe e gerar comportamentos inesperados no sistema.
Acredito que esses dois são os principais motivos para que o Singleton tenha esse estigma, mas na minha opinião ele é um padrão como qualquer outro; tem suas vantagens e desvantagens, e cabe ao desenvolvedor ter a sabedoria para saber quando e onde usá-lo.
Conclusão
Como falei anteriormente, esse artigo é o primeiro de uma série que pretendendo escrever para compartilhar os meus estudos com a comunidade. Comecei falando do Singleton por ser um padrão bastante famoso e de fácil compreensão. Espero que com esses pequenos passos tenham mostrado como podemos facilmente criar a nossa classe usando o Singleton no PHP.