O documento discute os princípios da programação orientada a objetos, como baixo acoplamento, alta coesão e programação voltada à interface. Também aborda tópicos como composição de comportamentos, evitar herança em favor da composição e cuidados com objetos mutáveis.
1. Programação Orientada a Objetos
Princípios OO
Pós Graduação em Análise e Desenvolvimento de Sistemas
Aplicados à Gestão Empresarial
INSTITUTO FEDERAL DE EDUCAÇÃO, CIÊNCIA E TECNOLOGIA
TRIÂNGULO MINEIRO – Campus Uberlândia Centro
Prof Carlos Eduardo Dantas – carloseduardodantas@iftm.edu.br
2. Prof Carlos Eduardo Dantas – carloseduardodantas@iftm.edu.br
Introdução
• Por que precisamos implementar baixo
acoplamento, alta coesão, dentre tanto
outros princípios e conceitos básicos em
POO?
3. Prof Carlos Eduardo Dantas – carloseduardodantas@iftm.edu.br
Curva de Defeitos do
Hardware
4. Prof Carlos Eduardo Dantas – carloseduardodantas@iftm.edu.br
Curva de Defeitos do
Software
5. Prof Carlos Eduardo Dantas – carloseduardodantas@iftm.edu.br
Análise - Curva de Defeitos
• Hardware se desgasta com o tempo;
• Software se deteriora com o tempo;
• Boa parte dos Software legados são
migrados para novas tecnologias por
deterioração, e não por necessidades
tecnológicas.
6. Prof Carlos Eduardo Dantas – carloseduardodantas@iftm.edu.br
Análise - Curva de Defeitos
• Um bom design de Software visa a uma
arquitetura flexível que permita futuras
alterações, facilitando a produção de
código organizado e legível, maximizando
seu reaproveitamento;
• Boas práticas OO procuram trazer os
benefícios mencionados acima para o
design.
7. Prof Carlos Eduardo Dantas – carloseduardodantas@iftm.edu.br
Programe voltado à Interface,
não à Implementação
• Contains() de ArrayList é uma busca muito
custosa em termos computacionais;
• Alternativas de coleções, como HashSet,
são mais eficientes, pois usam
internamente uma tabela Hash.
8. Prof Carlos Eduardo Dantas – carloseduardodantas@iftm.edu.br
Programe voltado à Interface,
não à Implementação
• O problema ao efetuar esta manutenção, é
que todo o código que usava o retorno do
método ArrayList será quebrado,
alterando todos os lugares que dependem
de alguma forma desse método;
• Tarefas do tipo search/replace são um
forte sinal de código ruim;
• Vincular os funcionários a uma
implementação específica de Collection,
caracteriza alto acoplamento.
9. Prof Carlos Eduardo Dantas – carloseduardodantas@iftm.edu.br
Programe voltado à Interface,
não à Implementação
• Quanto menos específica for a
interface/classe referenciada, menor o
acoplamento e mais possibilidades de
diferentes implementações;
• Como consequência, o código cliente terá
uma gama menor de métodos que podem
ser invocados.
10. Prof Carlos Eduardo Dantas – carloseduardodantas@iftm.edu.br
Programe voltado à Interface,
não à Implementação
• Devemos procurar um balanço entre o
desacoplamento e a necessidade do nosso
código;
• Princípio de Segregação de Interfaces –
clientes não devem ser forçados a
depender de interfaces que não usam.
11. Prof Carlos Eduardo Dantas – carloseduardodantas@iftm.edu.br
Programe voltado à Interface,
não à Implementação
• Hibernate usa uma implementação
específica de List, mas sempre retorna List
para evitar quebra de compatibilidade
com o código-fonte da aplicação cliente.
12. Prof Carlos Eduardo Dantas – carloseduardodantas@iftm.edu.br
Programe voltado à Interface,
não à Implementação
• E se quisermos receber objetos via socket
(SocketInputStream), como faz?
• Utilize sempre o tipo menos específico
possível.
13. Prof Carlos Eduardo Dantas – carloseduardodantas@iftm.edu.br
Programe voltado à Interface,
não à Implementação
• Geralmente, para a API JDBC, utiliza-se
uma Connection, ao invés de
OracleConnection, MysqlConnection,
dentre outros.
14. Prof Carlos Eduardo Dantas – carloseduardodantas@iftm.edu.br
Programe voltado à Interface,
não à Implementação
• Interfaces irão ajudar muito para evitar
instruções switch, ou mesmo um
excessivo número de ifs encadeados,
evitando acoplamentos no modelo,
ocorrendo mudanças frequentes toda vez
que uma nova entidade for adicionada no
domínio.
15. Prof Carlos Eduardo Dantas – carloseduardodantas@iftm.edu.br
Programe voltado à Interface,
não à Implementação
• No projeto criado nas aulas anteriores, os
casos abaixo estão respeitando esse
princípio
16. Prof Carlos Eduardo Dantas – carloseduardodantas@iftm.edu.br
Programe voltado à Interface,
não à Implementação
• Contudo, ClienteView não está
respeitando, gerando um alto
acoplamento com ClienteControl.
17. Prof Carlos Eduardo Dantas – carloseduardodantas@iftm.edu.br
Programe voltado à Interface,
não à Implementação
• O certo seria criar interfaces e factories
para o Control, visando desacoplar o
máximo possível;
• Contudo, neste caso, como existe uma
implementação de Beans Binding entre o
view e o Control, o prejuízo deste
acoplamento é bastante minimizado.
18. Prof Carlos Eduardo Dantas – carloseduardodantas@iftm.edu.br
Componha Comportamentos
• Códigos são mais fáceis de entender e
manter quando possuem poucas
possibilidades de fluxos lógicos, ou seja,
poucos caminhos de execução.
19. Prof Carlos Eduardo Dantas – carloseduardodantas@iftm.edu.br
Componha Comportamentos
• Quantas possibilidades diferentes existem
para a execução deste método?
20. Prof Carlos Eduardo Dantas – carloseduardodantas@iftm.edu.br
Componha Comportamentos
• Existem diversas responsabilidades de
execução para esta classe;
• Este comportamento pode ser composto
por diversas partes menores, por isso
refatorações podem ser executadas.
21. Prof Carlos Eduardo Dantas – carloseduardodantas@iftm.edu.br
Componha Comportamentos
22. Prof Carlos Eduardo Dantas – carloseduardodantas@iftm.edu.br
Componha Comportamentos
23. Prof Carlos Eduardo Dantas – carloseduardodantas@iftm.edu.br
Componha Comportamentos
• Observa-se que, passando de estruturado
para OO, o sistema ganhou
4 novas classes e uma
Interface.
24. Prof Carlos Eduardo Dantas – carloseduardodantas@iftm.edu.br
Componha Comportamentos
• O comportamento foi quebrado em
diversas partes, onde foram juntados
novamente através de composição;
• O polimorfismo permite trabalhar de
maneira uniforme com partes que
executam tarefas distintas.
25. Prof Carlos Eduardo Dantas – carloseduardodantas@iftm.edu.br
Componha Comportamentos
• Ao implementar os métodos da Interface
Processo na classe Transferência, observa-
se que o Princípio de Segregação de
Interfaces foi violado.
26. Prof Carlos Eduardo Dantas – carloseduardodantas@iftm.edu.br
Componha Comportamentos
• Neste caso, o ideal é quebrar as interfaces
em uma hierarquia, assim como existe a
hierarquia entre Collection e
List/Set/Map;
• Caso o projeto não seja refatorado agora,
existe uma grande chance de sofrer novo
refactoring posteriormente, mesmo que a
implementação deste método seja simples.
27. Prof Carlos Eduardo Dantas – carloseduardodantas@iftm.edu.br
Evite Herança, favoreça
composição
• O maior problema da Herança é que
acoplamos a implementação da classe mãe
muito precocemente, criando a
necessidade da classe filha conhecer muito
bem o código interno da classe mãe, o que
é visto como quebra de encapsulamento.
28. Prof Carlos Eduardo Dantas – carloseduardodantas@iftm.edu.br
Evite Herança, favoreça
composição
• Exemplo: Herança entre Hashtable e
Properties.
29. Prof Carlos Eduardo Dantas – carloseduardodantas@iftm.edu.br
Evite Herança, favoreça
composição
• A motivação dos desenvolvedores da JDK é
válida: o reaproveitamento de código já escrito
na classe Hashtable;
• Usar composição permite o reaproveitamento de
código sem o efeito indesejado de quebra de
encapsulamento;
• No exemplo da jdk, bastaria a classe Properties
fazer associação para um Hashtable privado, e o
método setProperty() delegar para a invocação
de hashtable.put()
30. Prof Carlos Eduardo Dantas – carloseduardodantas@iftm.edu.br
Evite Herança, favoreça
composição
• Ao substituir herança por interface, as
vantagens do polimorfismo permanecem,
e o acoplamento é bem menor, já que
nenhuma dessas classes precisam
conhecer o funcionamento interno de
outras, especialmente da classe mãe.
31. Prof Carlos Eduardo Dantas – carloseduardodantas@iftm.edu.br
Evite Herança, favoreça
composição
• No projeto das aulas anteriores, ficou claro
que PedidoDaoImpl e ClienteDaoImpl
ficaram livres com o comportamento de
Composição
32. Prof Carlos Eduardo Dantas – carloseduardodantas@iftm.edu.br
Cuidado com o modelo
anêmico
• Um dos pilares de POO é que não se deve
expor os detalhes de implementação;
• Encapsulando a implementação, pode-se
trocar com facilidade, já que não existe
outro código dependendo destes detalhes;
• O usuário poderá acessar o objeto através
do contrato definido pela interface
pública.
33. Prof Carlos Eduardo Dantas – carloseduardodantas@iftm.edu.br
Cuidado com o modelo
anêmico
34. Prof Carlos Eduardo Dantas – carloseduardodantas@iftm.edu.br
Cuidado com o modelo
anêmico
• No exemplo da classe Conta, o método
setSaldo() feriu o encapsulamento, já que
dificilmente o saldo de uma conta será
simplesmente “substituído” por outro;
• Para alterar o saldo, faz mais sentido alguma
operação como saque() e deposito();
• Nunca crie um getter/setter sem uma
necessidade real;
• Códigos como conta.setSaldo(conta.getSaldo() +
100) estarão espalhados por toda a aplicação.
35. Prof Carlos Eduardo Dantas – carloseduardodantas@iftm.edu.br
Cuidado com o modelo
anêmico
• Caso a aplicação precise modificar para
que uma taxa seja debitada toda vez que
for realizado um depósito, será necessário
percorrer todo o código e modificar
diversas invocações, usando
search/replace.
36. Prof Carlos Eduardo Dantas – carloseduardodantas@iftm.edu.br
Cuidado com o modelo
anêmico
37. Prof Carlos Eduardo Dantas – carloseduardodantas@iftm.edu.br
Cuidado com o modelo
anêmico
• O código de exemplo é bem procedural, pois não
possui atributos, e excesso do uso de métodos
como funções;
• A classe Banco possui uma intimidade
inapropriada com a classe Conta, pois conhece
demais a sua implementação interna;
• Falta de uso do princípio Tell, Don´t Ask;
• Está rompendo o princípio básico de manter
comportamento e estado relacionados em uma
única classe.
38. Prof Carlos Eduardo Dantas – carloseduardodantas@iftm.edu.br
Cuidado com o modelo
anêmico
39. Prof Carlos Eduardo Dantas – carloseduardodantas@iftm.edu.br
Cuidado com o modelo
anêmico
• Enriqueça as classes com métodos de negócio,
para que não se tornem apenas estruturas de
dados;
• Algumas vezes getters/setters são necessários,
mas cuidado no uso indiscriminado destes.
40. Prof Carlos Eduardo Dantas – carloseduardodantas@iftm.edu.br
Cuidado com o modelo
anêmico
• No projeto da aula anterior, rapidamente foi
percebido que para validar as entidades, nada
melhor do que delegar este comportamento às
mesmas.
41. Prof Carlos Eduardo Dantas – carloseduardodantas@iftm.edu.br
Cuidado com objetos
mutáveis
• Objetos mutáveis são passíveis de efeitos
colaterais, gerando bugs indesejáveis.
42. Prof Carlos Eduardo Dantas – carloseduardodantas@iftm.edu.br
Cuidado com objetos
mutáveis
• Objetos imutáveis são muito mais simples de
manipular, e possuem comportamento
previsível.
43. Prof Carlos Eduardo Dantas – carloseduardodantas@iftm.edu.br
Cuidado com objetos
mutáveis
• Objetos mutáveis são imprevisíveis, pois no
exemplo abaixo é impossível determinar que a
saída será o ano atual;
• Como solução, muitos criam cópias defensivas
dos objetos, como:
44. Prof Carlos Eduardo Dantas – carloseduardodantas@iftm.edu.br
Referências
• SILVEIRA, Paulo, Guilherme. LOPES, Sérgio.
MOREIRA, Guilherme, SEPPAT, Nico. KUNG,
Fábio. Introdução à Arquitetura e Design de
Software. Editora Campus, 2012;
• PRESSMAN, Roger. Engenharia de Software –
Uma abordagem Profissional – 7ª edição, 2011;
• ANICHE, Maurício. Orientação a objetos e
SOLID para Ninjas. Casa do Código, 2015;
• GUERRA, Eduardo. Design Patterns com Java.
Casa do Código, 2014.