O documento discute os fundamentos e princípios do projeto orientado a objetos, abordando conceitos como abstração, classes e objetos, encapsulamento, herança, polimorfismo, relacionamentos entre classes, interdependência, qualidade de projeto e princípios como responsabilidade única, aberto-fechado, substituição de Liskov, inversão de dependência, reuso por composição e segregação de interface.
Fundamentos e princípios do projeto orientado a objetos
1. Fundamentos e Princípios do Projeto
Orientado a Objetos
Autor: Evandro João Agnes
evandroagnes@yahoo.com.br
2. Abstração
Seleção de alguns aspectos relevantes a uma
determinada análise, suprimindo outros
Serviços e atributos aplicáveis a objetos dentro de um
determinado contexto
2
3. Classes e Objetos
Classe
Descrição de um conjunto de objetos similares
Abstratas ou Concretas
Objeto
Reúnem na mesma estrutura:
Atributos (dados) que definem o estado
Operações que definem o comportamento e manipulam os dados
Identidade de objetos
Retenção de estado
3
4. Encapsulamento
Esconder detalhes de implementação do estado e
comportamento do objeto
Objetos são acessados apenas pela interface externa
definida para eles
Detalhes de implementação das classes podem ser
alterados sem que as aplicações necessitem de
alterações
4
5. Mensagem
Comunicação feita entre objetos
Chamadas a métodos
5
6. Herança
Permite que novas classes sejam construídas usando
código e características declaradas em outras classes
Relação do tipo “é um” entre classes
Super-classes e sub-classes
Sub-classe herda todos atributos e métodos da super-classe
6
7. Polimorfismo
Propriedade na qual uma chamada genérica de um
método pode ser executada de diferentes maneiras de
acordo com o objeto que fez a chamada
Exemplo
Classe Reta: método desenhar()
Classe Círculo: método desenhar()
7
8. Relacionamentos
Associação
Relação do tipo “tem um” entre objetos
Agregação
Relação do tipo “todo-parte”
Dependência fraca
Composição
Relação do tipo “todo-parte”
Dependência forte
8
9. Interdependência
Elementos que compartilham alguma necessidade
Tipos de Interdependência
Nome
Tipo ou classe
Convenção
Algoritmo
Posição
Valor
Identidade
9
10. Interdependência
Princípios
Minimizar a interdependência total através do
encapsulamento
Minimizar qualquer interdependência que cruze as
fronteiras do encapsulamento
Maximizar a interdependência dentro das fronteiras do
encapsulamento
Abusos
Função amigável
Herança sem restrição
Detalhes internos do algoritmo de uma classe relevantes
para outras classes
10
11. Domínios
Domínio de Apresentação Baixa
reutilização
Domínio de Aplicação
Média
Domínio de Negócio reutilização
Domínio de Arquitetura
Alta
Domínio de Base reutilização
11
12. Grau de dependência ou acoplamento
Conjunto de classes que uma classe se baseia para
operar
Grau de dependência pode ser
Direto
Indireto
Classes em domínios altos tem alto grau de
dependência indireto e classes em domínios baixos
tem baixo grau de dependência indireto
12
13. Grau de dependência ou acoplamento
Acoplamento é o caminho para
o Lado Negro da Força!
Conduz para complexidade
Conduz para confusão
Conduz ao sofrimento
Uma vez que você inicie o
caminho para o Lado Negro, ele
sempre irá dominar seu destino.
“Consumir você ele irá!”
Desacoplar através de abstrações
e interfaces!
13
14. Lei de Demeter
Cada unidade deve conhecer apenas unidades
intimamente relacionadas a ela
Segundo a Lei de Demeter as mensagens devem ser
enviadas apenas para:
si mesmo - métodos do objeto
seus objetos - atributos da instância
parâmetros recebidos pelo método
objetos criados pelo método
14
15. Coesão
Classes com alta coesão
Todas as características contribuem para a abstração de
tipo implementada pela classe
Classes com baixa coesão
Apresenta um conjunto de características diferentes
15
16. Problemas de coesão
Coesão de instância mista
Ter algumas características que são definidas apenas para
alguns objetos da classe
Coesão de domínio misto
Uma classe contém um elemento que cria dependência com
uma classe de domínio diferente que não tem qualquer tipo
de negócio com a classe*
Coesão de papel misto
Uma classe contém um elemento que diretamente cria
dependência de uma classe de mesmo domínio que não tem
qualquer tipo de negócio com a classe*
* Uma classe B não tem qualquer tipo de negócio com A se A
puder ser plenamente definida sem qualquer noção de B
16
20. Espaço-estado e comportamento
Espaço-estado de uma classe é a totalidade de estados
permitidos para qualquer objeto da classe
Cada componente do estado (atributos) de um objeto
define uma dimensão
É o conjunto de valores de dimensões válidas para
um objeto
O modo como o objeto muda de estado é o seu
comportamento
O comportamento permitido de uma classe é o
conjunto de transições que o objeto pode fazer entre
os estados do espaço-estado
20
21. Espaço-estado e comportamento
O espaço-estado de uma subclasse deve estar contido
inteiramente dentro do espaço-estado da superclasse
O espaço-estado de uma subclasse pode ter mais
dimensões que a superclasse
21
22. Invariante de classe
Condição que todo objeto da classe deve satisfazer em
todo o seu ciclo de vida
São restrições no espaço-estado do objeto
A invariante nunca deve ser quebrada
22
23. Pré-condições e pós-condições
Devem garantir a invariante do objeto
Toda operação tem uma pré-condição e uma pós-
condição
A pré-condição é uma condição que deve ser
verdadeira quando a operação começar a executar
A pós-condição é uma condição que deve ser
verdadeira quando a operação finalizar sua execução
23
24. Conformidade de tipo
Um sub-tipo deve se conformar a seu super-tipo
O sub-tipo pode ser utilizado em qualquer contexto
em que o super-tipo seja esperado
A invariante da subclasse deve ser pelo menos tão
forte quanto a invariante da super-classe
A pré-condição de qualquer operação deve ser igual
ou menos restritiva que a operação correspondente
da super-classe
A pós-condição de qualquer operação deve ser igual
ou mais restritiva que a operação correspondente na
super-classe
24
25. Comportamento fechado
O comportamento herdado deve respeitar a
invariante da sub-classe
Nem sempre é possível, neste caso deve-se efetuar
alguma ação corretiva
evitar herança dos métodos que não respeitem a invariante
suprimir os métodos de modo que ele não tenha efeito
(possivelmente lançando uma exceção)
estar preparado para reclassificar o objeto
25
27. Projeto Ruim
Rígido
Difícil de alterar
Uma alteração requer uma cascata de outras alterações
Impacto das alterações não consegue ser previsto
Frágil
A cada alteração novos erros aparecem em áreas
aparentemente desconectadas
Imobilizado
Sem muita possibilidade de reuso
Partes desejadas de um componente possui muitas partes
indesejadas para o reuso
27
28. Projeto Ruim
Pegajoso
Alterações corretas são mais difíceis de fazer que as
erradas (bacalhau!)
Obscuro
Difícil de entender
Complexidade desnecessária
Repetição desnecessária
28
29. Princípios de Projeto
Princípio da Responsabilidade Única
The Single Responsibility Principle (SRP)
Princípio do Aberto-Fechado
The Open-Closed Principle (OCP)
Princípio de Substituição de Liskov
The Liskov Substitution Principle (LSP)
29
30. Princípios de Projeto
Princípio da Inversão de Dependência
Dependency Inversion Principle (DIP)
Princípio de Reuso de Composição
The Composite Reuse Principle (CRP)
Princípio de Segregação de Interface
The Interface Segregation Principle (ISP)
30
31. The Single Responsibility Principle
Uma classe deveria ter apenas uma razão para mudar
Responsabilidade = razão para mudança
Múltiplas responsabilidades = acoplamento alto,
baixa coesão
Responsabilidades são eixos de alteração
Se uma classe faz mais de uma coisa, separe em
classes diferentes
31
34. The Single Responsibility Principle
Exemplo de código...
public class Grupo {
private List servidores;
public List getServidores() {
return servidores;
}
public void setServidores(List servidores) {
this.servidores = servidores;
}
}
public class Servidor {
private String login;
private Grupo meuGrupo;
public Servidor (String login, Grupo grupo) {
this.login = login;
this.meuGrupo = grupo;
meuGrupo.getServidores().add(this.login);
}
}
34
35. The Single Responsibility Principle
E se alterarmos a lista de servidores para um HashMap?
public class Grupo {
private HashMap servidores;
public HashMap getServidores() {
return servidores;
}
public void setServidores(HashMap servidores) {
this.servidores = servidores;
}
}
A classe Servidor precisa ser alterada também...
public class Servidor {
private String login;
private Grupo meuGrupo;
public Servidor (String login, Grupo grupo) {
this.login = login;
this.meuGrupo = grupo;
meuGrupo.getServidores().put("login", this.login);
}
35 }
36. The Single Responsibility Principle
Se a regra para incluir servidor for responsabilidade do Grupo, o
código da classe Servidor não precisa ser alterado...
public class Grupo {
private HashMap servidores;
public void incluirServidor(Servidor servidor){
// Regra para inserir Servidor...
}
}
public class Servidor {
private String login;
private Grupo meuGrupo;
public Servidor (String login, Grupo grupo) {
this.login = login;
this.meuGrupo = grupo;
meuGrupo.incluirServidor(this);
}
}
36
37. The Open-Closed Principle
Classes devem estar abertas para extensão e fechadas
para modificação
Quando os requisitos mudam (e eles mudam!) o
projeto deve permitir estender o comportamento
adicionando novo código e não alterando o
comportamento do código existente
Se a alteração de uma classe ou método resultar em
uma cascata de alterações em outras classes e
métodos, você tem um projeto “ruim”
37
38. The Open-Closed Principle
Separe o que varia
Encapsular o que varia para que não afete o resto do
código
Menos conseqüências indesejadas
Mais flexibilidade
Abstração e polimorfismo são a chave para este
princípio
38
39. The Open-Closed Principle
public class Matricula {
private BigDecimal totalCred;
private String tipoMatr;
private Obrigacao obrigacao;
public void matricular(){
// ...
obrigacao.calcular(totalCred, tipoMatr);
}
}
public class Obrigacao {
public BigDecimal calcular(BigDecimal creditos, String tipo){
BigDecimal valor = null;
if (tipo.equals("curricular")) {
// Calcula matricula curricular
} else if (tipo.equals("extra-curricular")){
// Calcula valor extra-curricular
} else {
// Calcula valor padrao
}
return valor;
}
}
39
41. The Liskov Substitution Principle
Conformidade de Tipo
Sub-tipos podem substituir super-tipos
Guia para criação de abstrações
Contratos
Violando este princípio podemos violar também o
Princípio do Aberto-Fechado
41
43. The Liskov Substitution Principle
public class Bolsa {
/**
* Pre-condicao: valor não pode ultrapassar o devido
* @param valor Valor do desconto lancado
*/
public void lancarDesconto(BigDecimal valor){
}
}
public class Financiamento extends Bolsa {
/**
* Pre-condicao: deve ser menor que o devido
* @param valor Valor do desconto lancado
*/
public void lancarDesconto(BigDecimal valor){
}
}
43
45. Dependency Inversion Principle
Dependa de abstrações (ou interfaces) e não de classes
concretas
Programe para uma interface, não para uma
implementação
Explora o polimorfismo
Interface pode ser um super-tipo
Alterações em classes que implementam uma interface não
quebram código cliente
45
47. The Composite Reuse Principle
Preferir a composição em relação a herança
Herança excessiva pode causar fragilidade e hierarquias
complexas de classes
Herança pode quebrar o encapsulamento
Com herança podemos sobrescrever um método, às
vezes indesejável. Na composição os métodos devem ser
utilizados como foram definidos
Novas funcionalidades podem ser agregadas sem
alteração no código existente (Princípio do Aberto-
Fechado)
47
48. The Composite Reuse Principle
Herança
Comportamento é herdado
Não podemos alterar o comportamento sem escrever mais
código
Composição
Comportamento como um atributo
Mais flexibilidade
Permite alterar o comportamento em tempo de execução
48
52. The Composite Reuse Principle
Mas...
Cálculo do bônus passou a ser diferente para os
empregados em tempo integral
O que fazer para garantir um bom reuso sem código
duplicado?
52
54. The Interface Segregation Principle
Interfaces para específicos tipos de cliente são
melhores que uma interface de propósito geral
Clientes não deveriam ser forçados a depender de
interfaces que eles não utilizam
Interfaces muito grandes podem introduzir
acoplamentos não desejados entre os clientes
ISP não recomenda que seja criada uma interface
para cada classe cliente, mas que as classes sejam
classificadas por tipo
Caso 2 ou mais tipos de clientes utilizem o mesmo
método, este deve estar em ambas interfaces
54
57. Referências
Fundamentals of Object-Oriented Design in UML -
Meilir Page-Jones
Head First Design Patterns - Elisabeth Freeman, Eric
Freeman, Bert Bates and Kathy Sierra
Design Principles e Design Patterns
http://www.objectmentor.com/resources/articles/Principles_and_Patterns.pdf
Domain Driven Design Quickly
http://www.infoq.com/minibooks/domain-driven-design-quickly
Contratos Nulos
http://fragmental.com.br/wiki/index.php/Contratos_Nulos
57
58. Referências
Lei de Demeter
http://c2.com/cgi/wiki?LawOfDemeter
Articles for Object Oriented Design
http://www.objectmentor.com/resources/publishedArticles.html
58