Entendendo o open/closed principle
1. Introdução
Se você é um programador(a) e trabalha com alguma linguagem orientada a objetos muito provavelmente já ouviu falar no acrônimo SOLID (criado pelo Michael Feathers ele representa os cinco principais conceitos identificados por Robert C. Martin na programação orientação a objetos).
Neste conjunto importantíssimos de conceitos o OCP(Open/Closed Principle) é representado pela letra O.
2. O que é
Este princípio consiste em sempre programar entidades de um sistema (classes, módulos, funções) abertas para extensões mas fechadas para modificações, de forma que seja possível adicionar novos comportamentos a funcionalidade criando novas classes ao invés de modificar as antigas.
Isso parece ser um pouco difícil de ser aplicado, porém, no decorrer desse artigo vamos observar como é simples e a importância de programar voltado a esse padrão.
3. Vantagens
Considerado o conceito com maior importância dentre os cinco por Robert C. Martin, porém, negligenciado pela maioria dos desenvolvedores esse principio traz inúmeras vantagens para qualquer sistema OO, algumas delas são:
- Reduz a complexidade ciclomática
- Facilita a manutenção
- Aumenta a escalabilidade
- Diminui o acoplamento
4. Caso de uso
Como podemos ver, nesse trecho de código existe um serviço de e-mails onde são feitas algumas verificações baseadas no tipo passado como parâmetro para definir o comportamento do método EnviarEmail.
public enum TipoEmail {
Texto,
Html,
Criptografado
}public class EmailService { public void enviarEmail(String mensagem, TipoEmail tipo) { if (tipo == TipoEmail.Texto) { removerFormatacao(mensagem); } else if (tipo == TipoEmail.Html) { inserirHtml(mensagem); } else if (tipo == TipoEmail.Criptografado) { criptografarMensagem(mensagem);
}
send(mensagem);
}
}
Vamos imaginar o seguinte cenário:
Nosso P.O solicita a adição de XML como tipo de e-mail, oque faremos?
A solução que vem a mente é:
public enum TipoEmail {
Texto,
Html,
Criptografado,
Xml
}public class EmailService { public void enviarEmail(String mensagem, TipoEmail tipo) { if (tipo == TipoEmail.Texto) { removerFormatacao(mensagem); } else if (tipo == TipoEmail.Html) { inserirHtml(mensagem); } else if (tipo == TipoEmail.Criptografado) { criptografarMensagem(mensagem);
}
else if (tipo == TipoEmail.Xml) { mapearParXml(mensagem);
}
send(mensagem);
}
}
Nesta abordagem sempre que houver necessidade de novas alterações (e você sabe que não são poucas vezes) será necessário a adição de um novo item no enum acompanhado do encadeamento de um novo if no método de envio.
Desta forma nosso serviço de e-mail tem um potencial enorme de crescimento e com isso o aumento exponencial da complexidade do código comprometendo os testes, a semântica do código e escalabilidade do sistema.
Para aplicar o Open/closed principle vamos utilizar a seguinte abordagem:
public interface Email {
void tratar();
}public class EmailCriptografado implements Email { @Override
public void tratar() { criptografarMensagem(mensagem);
}
}public class EmailHtml implements Email {
@Override
public void tratar() { inserirHtml(mensagem);
}}public class EmailTexto implements Email { @Override
public void tratar() { removerFormatacao(mensagem);
}
}public class EmailXml implements Email { @Override
public void tratar() { mapearParXml(mensagem);
}
}
Como existem vários tipos de e-mail e obrigatoriamente eles terão estratégias diferentes para tratar a mensagem, criamos uma interface chamada “Email” que terá um método chamado tratar, assim para cada tipo será criado uma classe que implementa Email e sobrescreve o método tratar.
E nossa classe de serviço fica assim:
public class EmailService { public void enviarEmail(Email email) { email.tratar(); send(email.getMensagem()); }
}
Como podemos observar cada classe e-mail tem sua própria maneira de tratar a mensagem, removendo todos os if’s que existiam no nosso serviço, e o melhor de tudo, quando for necessário a adição de outro tipo só precisamos criar outra classe que implementa Email, promovendo um código realmente aberto a novas implementações e fechado para modificações.
5. Considerações finais
O mais importante é não se apegar a implementações e sim a conceitos e sempre se esforçar para aplicá-los no dia a dia. Caso não tenha ficado claro, segue alguns artigos que abordam o mesmo tema de outra forma:
- https://www.devmedia.com.br/open-closed-principle/18970
- https://www.eduardopires.net.br/2013/05/open-closed-principle-ocp/
- https://stackify.com/solid-design-open-closed-principle/
- http://www.andrecelestino.com/solid-open-closed-principle-ocp/
- http://joelabrahamsson.com/a-simple-example-of-the-openclosed-principle/
- https://medium.com/@gabriellamedas/ocp-the-open-closed-principle-b994922bed94