Fala ai Radizeiros e Radizeiras, tudo bem com vocês?
Quantas vezes a solução que você precisava para atender a uma solicitação de um cliente, ou corrigir algo, era adicionar vários “if” e “else” dentro do seu código?
Você sabe que eu prezo muito por qualidade de código e práticas como essa é uma violação de um dos princípios do SOLID.
Neste post estarei falando do segundo princípio do SOLID, o OCP – Open/Closed Principle (Princípio do aberto/fechado).
Este princípio diz que toda classe deve estar aberta a extensões e fechada para modificações.
Vamos direto ao ponto, para que fique mais claro esse princípio.
No código abaixo temos uma classe que cria arquivos, e na implementação do método GerarArquivos é algo que muito programadores fazem.
type TArquivo = class procedure GerarWord; procedure GerarPDF; procedure GerarXML; procedure GerarArquivos(Tipo : String); end; … procedure TArquivo.GerarArquivos(Tipo : String); begin if Tipo = 'Word' then GerarWord else if Tipo = 'PDF' then GerarPDF else if Tipo = 'XML' then GerarXML; end;
Mas isso funciona?
Com toda certeza.
Quem nunca fez isso atire a primeira pedra…rsrs
Quem nunca fez uma implementação como essa?
Isso funciona, só que é uma prática de programação terrível.
Nós não estamos obedecendo o princípio do aberto/fechado.
Imagina se tenho que gerar os arquivos em mais de um lugar, se esse método está em outros lugares, para todos os lugares que eu tenha que mexer, irei ter que implementar outros “if” e “else”, para saber qual o tipo do arquivo e por aí vai.
Se eu precisar depois colocar um outro tipo de arquivo, vou ter que ir de novo colocar mais um if, e se eu faço isso em mais de um lugar, tenho que implementar em todos os outros lugares, isso é uma prática de programação terrível.
Mas você pode estar pensando, isso é só um “if” e “else”, que mal tem isso aí…
Verdade é só um “if” e “else”, mas isso pode te dar uma dor de cabeça muito grande, vai ter que ficar debugando o código para achar o que for e o que está fazendo, e ainda mais em questão de “estética do código” seu código fica totalmente aerodinâmico, porque ele vai cada vez mais se afastando da margem, e todas as vezes que o código estiver se afastando da margem não é legal, irá trazer problemas para você.
A mas você pode estar pensando numa solução, certo?
Vou colocar um switch case…
Nossa, você achou a solução!!!!
Mas te digo uma coisa, não mudou nada, porque a mesma dificuldade que você irá ter para criar um novo tipo no switch case vai ter igual ao do “if” e “else”!
Seu código não irá ficar legar escrito desse jeito, é uma violação das boas regras, boas práticas de programação.
Tá certo, então como eu resolvo o princípio do aberto/fechado?
Como esse meu método irá ficar fechado para modificação e aberto para extensão?
Quando falamos que ele tem que estar fechado para modificações, por exemplo, eu tenho o meu GerarArquivos, eu preciso colocar um novo arquivo TXT, eu tenho que ser capaz de utilizar o método de GerarArquivos sem precisar mexer nele.
Como iremos fazer isso então?
Simples, abstração, polimorfismo, coisas que vimos muito na programação orientada a objetos.
Veja como no código abaixo foi refatorado o código anterior para estar em conformidade com as boas práticas.
type TArquivo = class procedure GerarArquivos; virtual; abstract; end; TArquivoWord = class(TArquivo) procedure GerarArquivos; override; end; TArquivoPDF = class(TArquivo) procedure GerarArquivos; override; end; TArquivoXML = class(TArquivo) procedure GerarArquivos; override; end;
Observe que tiramos todos métodos e separamos, no método GerarArquivos colocamos ele como virtual e abstract, neste caso nosso método pode ser sobrescrito, é um método que não precisa ser implementado na classe Arquivo mas ela pode ser sobrescrita em outras classes que vão herdar da classe Arquivo.
Agora dentro do nosso formulário no onClick do botão, como você pode observar no código abaixo, que criei uma variável que estende da classe TArquivoWord, eu poderia estender essa minha variável de qualquer uma das classe de arquivos.
procedure TForm2.Button1Click(Sender: TObject); var Arquivo : TArquivoWord; begin Arquivo := TArquivoWord.Create; try Arquivo.GerarArquivos; finally Arquivo.Free; end; end;
O método GerarArquivo agora está funcionando para qualquer um que seja as minhas implementações, e por que isso está aberto para extensão e fechado para modificação?
Porque agora sem eu precisar mexer no método GerarArquivos, posso acrescentar uma nova classe, por exemplo, ArquivoTXT.
... TArquivoTXT = class(Tarquivo) procedure GerarArquivos; override; end; ...
E em algum lugar no meu software que necessite de gerar arquivos TXT, eu simplesmente instancio ele.
procedure TForm2.Button1Click(Sender: TObject); var Arquivo : TArquivoTXT; begin Arquivo := TArquivoTXT.Create; try Arquivo.GerarArquivos; finally Arquivo.Free; end; end;
Desta forma eu não preciso mais mexer na implementação do Word, do PDF, do XML, e nem no método de GerarArquivos.
Não precisa mexer em nenhum deles, porque eles estão fechados para modificações, porém esse método está aberto para extensões , eu consigo assim gerar quantos arquivos eu quiser, cada um trabalhando na sua responsabilidade, sem um afetar o outro, usando POO puro, com abstração e polimorfismo.
Esse post faz parte de um dos meus treinamentos a CERTIFICAÇÃO ESPECIALISTA EM CLEAN CODE E BOAS PRÁTICAS DE PROGRAMAÇÃO.
A Certificação Especialista em Clean Code e Boas Práticas de Programação dará a você a oportunidade de melhorar seu software, otimizar o seu tempo e te dar a possibilidade de atender melhor os seus clientes. Conhecer a fundo essas técnicas e utilizar todos os seus benefícios irá facilitar muito a sua vida quando houver necessidade por parte de um cliente de um update rápido ou resolver um problema.