Alura > Cursos de Programação > Cursos de PHP > Conteúdos de PHP > Primeiras aulas do curso Design Patterns em PHP: padrões criacionais

Design Patterns em PHP: padrões criacionais

Criando Flyweights - Introdução

Olá pessoal, boas-vindas à Alura. Meu nome é Vinícius Dias, e vou guiar vocês nesse treinamento de Design Patterns em PHP: Padrões criacionais. Nesse treinamento vamos começar falando sobre a continuação do padrão Flywheight, que foi visto no treinamento de padrões de projetos estruturais.

Nesse padrão, existe o que é chamado de Flyweight Factory, onde criamos os objetos que implementam o padrão Flyweight, e conseguimos implementar um cash utilizando eles.

Falando em fábrica de objetos, também vamos aprender sobre o padrão Factory Method. Nesse padrão Factory Method vamos ver como implementar um gerenciador de logs, onde além fazer o log, vamos ver como criar loggers, ou escritores de log específicos, sejam eles escrevendo em arquivos, escrevendo na saída padrão. E isso tudo vai abstraído utilizando o Factory Method, que é outro padrão de projeto.

Vamos falar também sobre o Abstract Factory, que é um padrão que permite que criemos objetos relacionados, utilizando uma única fábrica. Dessa forma não acabamos com objetos misturados, de tipos diferentes.

Ainda no assunto de criação de objetos, vamos falar sobre como criar objetos complexos. Para isso vamos utilizar o Builder, que fornece uma interface um pouco mais amigável para criarmos objetos, e ainda vamos ver como especializar mais os nossos builders. Ao ver isso, veremos que é possível colocar determinadas regras dentro do nosso padrão Builder, para facilitar a construção.

Ao vermos o padrão Prototype, veremos que “PHP” já oferece uma forma muito mais simples de criar clones, ou cópias de objetos. Veremos como implementar o padrão Singleton, e esse padrão é o que permite que controlemos o número de instâncias, fazendo com que independente do número de vezes que eu tente acessar uma instância, eu sempre busque a mesma instância. Ou seja, eu tenho apenas uma instância durante todo meu projeto.

Sei que é bastante coisa, e se combinar com todos os padrões que já vimos até aqui, é bastante coisa ainda. Mas eu te convido a estudar com bastante atenção, porque é um conteúdo que vale muito a pena e pode ser necessário na nossa vida como desenvolvedor(a).

Espero que você aproveite bastante. Se no decorrer do curso ficar alguma pergunta, você pode abrir uma dúvida no fórum. Eu tento responder sempre que possível, mas quando não consigo, a nossa comunidade de alunos é muito solícita e com certeza alguém vai te ajudar.

Então te espero no próximo vídeo para fazermos uma revisão do que foi visto no último treinamento, e começar a pôr a “mão na massa”. Te vejo lá.

Criando Flyweights - Revisão

Olá, pessoal. Vamos fazer uma revisão bem rápida do último padrão que vimos no treinamento de padrões de projetos estruturais com “PHP”.

Falamos sobre o padrão Flyweight. Ele deve ser utilizado quando tivermos muitas instâncias em memória, de algum objeto pesado. Por exemplo, tínhamos 10000 instancias do objeto “Pedido” sendo salvas em memória, e todas ao mesmo tempo, ou seja, tínhamos um consumo de memória bem grande.

E para poder otimizar os recuso do computador, extraímos uma parte do pedido que poderia ser compartilhada, para uma outra classe, e chamamos de DadosExtrinsecosPedido. Esse nome ruim foi dado propositalmente, para vermos que esse padrão tem um contraponto bem forte.

Aumentamos a complexidade do código a ponto de que se uma pessoa simplesmente der uma olhada nessa classe, ela vai pensar “não faz o menor sentido isso ser uma classe externa, vou internalizar esses dados e trazer para meu pedido”. Então é muito comum esse problema surgir. Mas como já entendemos esse problema no treinamento anterior, vou dar um nome menor para essa classe.

Então no “phpstorm” vou clicar “Shift + F6”, e vou chamar de TemplatePedido. Então a propriedade $dados vai ser renomeada com “Shift + F6”, para $template. Ao invés de serem os dados, é um template do pedido, e que depois, com esse template, eu posso criar vários pedidos. Os pedidos podem ter um orçamento, um ID ou algo mais específico. No nosso exemplo ele tem que ser só o orçamento.

“Beleza Vinícius, mas isso nós já aprendemos no último treinamento, e você disse que esse treinamento seria de padrões criacionais. Como criar objetos de forma mais interessante”, pois é. Temos em “pedidos.php”, criando um template do pedido, definindo um template do pedido, e só então, definindo um orçamento.

Seria interessante se eu tivesse alguma forma de criar essa linha “10”, alguma classe ou alguma função. Estou criando um pedido para um cliente de nome fictício, e com a data new \DateTimeImmutable(), me dá o pedido.

Essa função, esse método de uma classe ou qualquer coisa, verificaria se já existe esse template da linha “10”, se já tem um pedido desse cliente para essa data, se tem, vou usar esse template no pedido, caso não, eu vou criar e armazenar em cash, esse template. E é isso que vamos fazer no próximo vídeo.

Criando Flyweights - Cache de objetos

Olá pessoal, bem vindos de volta! Vamos implementar aquilo que comentei no último vídeo, para isso, primeiro vamos organizar um pouco. Como eu falei, nesses treinamentos de padrão de projeto, não estou focando em arquitetura, então têm muitas classes na raiz.

Para não me perder, vou criar uma nova pasta em “projeto > src”, e vou chama-la de “Pedido. Tanto “Pedido.php”, quanto “TemplatePedido.php”, eu vou em “Refactor”, e move-los para a pasta “Pedido”. Agora vou alterar o namespace para isso tudo bater correto. Alterei o namespace, agora tenho que corrigir aqui.

O que eu fiz foi mover minhas classes para uma pasta chamada “Pedido”. Agora vou corrigir na linha “8”, porque o pedido precisa de um orçamento, então “Alt + Enter” e importar, porque agora o orçamento está em um namespace diferente.

Feita essa pequena correção, vou criar uma nova classe, e essa classe vou chamar de “CriadorDePedido”. E o que essa classe vai fazer? Criar um novo método com criaPedido, e esse pedido vai ser criado para esse nome de cliente $nomeClient, para uma data que vou passar como string, uma data formatada, e o orçamento. São esses dados que um pedido precisa.

Deixa eu quebrar a linha aqui, assim vocês conseguem enxergar melhor, e vou inicializar essas propriedades, na verdade, não preciso inicializá-las.

O que eu vou fazer? Primeiro, se eu fosse simplesmente criar o pedido, eu criaria o template new Templatepedido, nesse templateeu poderia passar o nome do cliente $nomeCliente, a data formatada new \DateTimeImutable($dataFormatada). Crio o pedido, nesse pedido eu tenho $template, $orcamento, e eu posso retornar o pedido.

Perfeito. Eu tenho meu criador de pedido, criando um pedido corretamente. Vou adicionar o tipo de retorno, que é um pedido. Mas provavelmente você está se perguntando para quê eu criaria isso, se no meu código eu estou tendo meu template de pedidos compartilhado?

Se eu utilizar a classe de criador de pedidos, volto para aquele problema de ter muitos objetos em memória; para todos vou sempre instanciar uma nova data, um novo template, então não funciona muito bem. O que vou fazer?

Sempre que alguém enviar uma chamada de método para criar um pedido, vou verificar se já existe um template com aquelas propriedades, se já existe um cliente criado com esse nome do cliente$nomeCliente e com essa data formatada $dataFormatada. Se não existir ainda, eu crio e salvo ele em algum lugar, caso já exista, eu simplesmente uso, e não instancio um novo objeto.

Vou criar privated array $templates = [ ]. Antes de inicializar o template, eu vou extrair o item copiado para um novo método, então com o botão direito eu clico em “Refactor > Extract Method”, depois vou “gerarTemplatePedido”. Então estou pegando meu template, e em gerarTemplatePedido, vou verificar se existe no cash.

Para armazenar no cash, vou utilizar uma solução que não é mais bonita, mas que vai funcionar. Vou pegar um hash, que vai ser $hash = md5($nome)Cliente . $dataFormatada). O nome do cliente, unido com a data formatada vai ser algo único para os templates, isso gera uma chave única. E vou gerar um hash disso, para ser uma string bem formatada, sem traços, espaços e esses tipos de coisas, para ficar uma chave mais formal.

Agora vou verificar se existe essa chave $hash na nossa rede templates. Se já existe, vou retornar nessa rede templates, essa chave. O que estou fazendo é verificar se em algum momento já salvei return $this ->templates[$hash] em cash, e caso não, vou criar um novo template e retornar. Só que em momento nenhum estou preenchendo esse template.

Vamos fazer esse preenchimento. Primeiro vou inverter a condição da linha “27”. Vou dizer que caso não exista cash nesses meus templates, eu vou criar esse novo template e salvar no meu cash. Então existindo ou não, vou sempre retornar o template do cash.

Vamos recapitular o que eu estou fazendo. Esse meu gerarTemplatePedido vai receber o nome do cliente, uma data formatada e vai devolver um template para o pedido. Estou pegando esse nome do cliente, juntando com uma string da data formatada e gerando hash, que será uma chave para eu salvar em cash.

Estou verificando se não existir no meu cash, que está lá em memória, eu vou criar esse novo template e salvar em cash. Agora se existir, ele não vai fazer nada nesse if, vai só retornar o cash já salvo. Então eu poupei memória.

Com isso, eu tenho um método que cria um pedido, e caso já tenha um pedido para esse cliente nessa data, ele vai usar um template já criado. Então vamos para os nossos pedidos, posso remover o texto da linha “10”, e agora para cada um dos pedidos, vou continuar criando um orçamento.

Então vou criar uma variável chamada “Orçamento”, só que agora não vou mais instanciar diretamente no pedido. Vou fazer com que o pedido seja no meu criado de pedido, então $pedido + $criadorPedido -> criaPedido( nomeCliente ‘Vinícius Dias’), não vou mais usar aquele hash feio. Então o cliente vai ser “Vinícius Dias”, a data vai ser $hoje, e ainda vamos criar essa variável, e $orçamento.

Qual é a data de hoje? Eu posso passar diretamente 2020-03-14, só que isso não é o dia “hoje” sempre, esse código só funciona no dia de hoje. Então eu posso utilizar uma função do próprio “PHP”; posso criar um novo objeto date time mutable, e chamar o método format para formatar e pegar a data atual, mas já existe uma função do “PHP” que faz esse processo de forma mais simples, chamado date.

Eu só informo para essa função em qual formato eu quero devolver a data, então date( format ‘y-m-d’). Com isso, estou criando um pedido para esse cliente, nessa data, com esse orçamento. Então esse template vai ser sempre o mesmo, vou ter um template só, sempre será usado o mesmo objeto.

Primeiro vou rodar para ver se funciona, e reparem, continuo usando aqueles 3 mega, não estou criando aquele mesmo template sempre. Agora no meu criador de pedidos, vou dar um vardump no template, e isso vai fazer meu código exibir os dados de cada template, de cada um dos pedidos.

Vou executar, e observem que ele mostra vários. Reparem no número “#5”, esse é o TemplatePedido número 5, mais acima também é o número 5. Ou seja, ele está sempre utilizando o mesmo template. Então nosso código funcionou, estamos gerando um cash corretamente.

Isso faz parte do padrão Flyweight, essa forma de cashear os objetos que podem ser compartilhados, faz parte do padrão Flyweight, e pode ser chamado de uma fábrica de Flyweight, Flyweight factory ou algo do tipo.

Se analisarmos aquele diagrama que eu sempre costumo mostrar, de cada um dos padrões, temos o Flyweight com os dados repetidos, o contexto que tem um estado único mais o objeto Flyweight que é aquele template, e nós temos a fábrica de Flyweight, que vai pegar aqueles dados, já utilizando os dados repetidos. Ou seja, ele não vai criar um template para cada pedido, ele vai tentar reutilizar.

Então, isso faz parte de um padrão estrutural, mas é, na verdade, uma forma de criar os objetos referentes a esse padrão estrutural. Então eu trouxe para esse curso os padrões criacionais porque o padrão Flyweight é complexo, difícil de utilizarmos, e têm essas duas partes. Com isso, temos um pafrão Flyweight completo.

Falando em criar pedidos, criar coisas, veremos no próximo capitulo, uma forma de gerar logs de algumas ações, e para gerar logs, precisamos criar um logger. Então vamos conversar sobre os problemas que isso traz, e algumas soluções possíveis.

Sobre o curso Design Patterns em PHP: padrões criacionais

O curso Design Patterns em PHP: padrões criacionais possui 107 minutos de vídeos, em um total de 54 atividades. Gostou? Conheça nossos outros cursos de PHP em Programação, ou leia nossos artigos de Programação.

Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:

Aprenda PHP acessando integralmente esse e outros cursos, comece hoje!

Conheça os Planos para Empresas