Escolar Documentos
Profissional Documentos
Cultura Documentos
Licença CC-BY; permite copiar, distribuir, adaptar etc; porém, créditos devem ser dados ao autor dos
1 slides
"O problema mais fundamental em Ciência da Computação é
a tarefa de decomposição de problemas: como dividir um
problema complexo em partes que possam ser resolvidas de
forma independente" -- John Ousterhout
2
Definição de Projeto de Software
● Frase de Ousterhout é uma excelente definição
● Projeto:
○ Quebrar um "problema grande" em partes menores
○ Resolução (ou implementação) das partes menores
resolvem (ou implementam) o "problema grande"
3
Project vs Design
● Em Inglês, temos duas palavras:
○ Project: esforço colaborativo para resolver problemas
○ Design: desenho ou proposta de uma solução
● Em Português, temos uma única palavra: projeto
● Neste módulo, projeto = design
4
Projetar = Quebrar em partes menores
● Exemplo: compilador
5
Módulos
● Em Engenharia de Software:
○ Partes menores = módulos (pacotes, componentes,
classes, etc)
6
O que vamos estudar? (parte 1)
● Propriedades de "bons projetos" de software
○ Integridade Conceitual
○ Ocultamento de Informação
○ Coesão
○ Acoplamento
7
O que vamos estudar? (parte 2)
● Princípios (ou diretrizes) para projeto de módulos com as
propriedades que estudamos antes:
○ Responsabilidade Única
○ Segregação de Interfaces
○ Prefira Interfaces a Classes
○ Aberto/Fechado
○ Demeter
8 ○ Substituição de Liskov
Propriedades de Projeto
9
Integridade Conceitual
10
Integridade Conceitual = coerência e padronização
de funcionalidades, projeto e implementação
Exemplo Contra-Exemplo
11
Mais um exemplo
Por que falta integridade conceitual nessas capas de slides?
12
Integridade Conceitual
● Decisões de um sistema devem ser coerentes
● Sejam elas sobre:
○ Funcionalidades
○ Interface com usuário
○ Projeto
○ Implementação
○ etc
13
Exemplo (referente a interface com o usuário)
● Botão "sair" é idêntico em todas as telas
● Se um sistema usa tabelas para apresentar resultados,
todas as tabelas têm o mesmo leiaute
● Todos os resultados são mostrados com 2 casas decimais
14
Exemplo
(referente a
funcionalidades)
15
Fonte: https://www.shopify.com/partners/blog/feature-creep
Integridade Conceitual vale também para o
projeto e código de um sistema
16
Exemplos (em nível de projeto/código)
● Todas as variáveis seguem o mesmo padrão de nomes
○ contra-exemplo: nota_total vs notaMedia
● Todas as páginas usam o mesmo framework (mesma versão)
● Se um problema é resolvido com uma estrutura de dados
X, todos os problemas parecidos também usam X
17
Integridade conceitual é a consideração mais
importante no projeto de sistemas -- Fred Brooks
18
Motivo: integridade conceitual facilita uso e
entendimento de um sistema
19
Ocultamento de Informação
(Information Hiding)
20
Origem do conceito (David Parnas, 1972)
21
22
placa modelo
23
Construtora, cria a
Hashtable
24
Problema: clientes precisam manipular uma estrutura de dados
interna da classe, para estacionar um veículo
25
Problema
● Classes precisam de um pouco de "privacidade"
● Até para evoluir de forma independente dos clientes
● Código anterior: clientes manipulam a hashtable
● Comparação: clientes não podem entrar na cabine do
estacionamento e eles mesmo anotar os dados do seu
carro no "livro" do estacionamento
26
Agora uma versão com ocultamento de
informação
27
1
28
2
29
3
31
Bom módulos são semelhantes a icebergs
(pequena parte pública e visível; grande parte submersa e privativa )
32
Fonte: Bertrand Meyer, Object-oriented software construction, 1997 (pág. 51)
Coesão
33
Coesão
● Uma classe deve ter uma única função, isto é, oferecer
um único serviço
● Vale também para outras unidades: funções, métodos,
pacotes, etc.
34
Contra-exemplo 1
35
Contra-exemplo 1
36
Contra-exemplo 2
37
Contra-exemplo 2
38
Exemplo
39
Acoplamento
40
Acoplamento
● Nenhuma classe é uma ilha ...
● Classes dependem umas das outras (chamam métodos
de outras classes, estendem outras classes, etc)
● A questão principal é a qualidade desse acoplamento
● Dois tipos:
○ Acoplamento aceitável ("bom")
○ Acoplamento ruim
41
Acoplamento Aceitável
● Classe A depende de uma classe B:
○ Mas a classe B possui uma interface estável
○ Classe A somente chama métodos da interface de B
42
Classe Estacionamento depende (está
acoplada) à classe Hashtable, mas
esse acoplamento é aceitável
43
Acoplamento Ruim
● Classe A depende de uma classe B:
a. Mas interface da classe B é instável
b. Ou então a dependência não ocorre via interface de B
44
Como uma classe A pode depender de uma
classe B sem ser via a interface de B?
45
B A
grava lê
"arq1.db
"
46
B A
grava lê
"arq1.db
"
47
Problema
● Classe B não sabe que a classe A é sua "cliente"
● Logo, B pode mudar o formato do arquivo ou mesmo
deixar de salvar o dado que é lido por A
B A
grava lê
"arq1.db
"
48
Tornando acoplamento ruim em bom
49
Tornando acoplamento ruim em bom
50
Resumo
● Acoplamento estático (ou estrutural):
○ Classe A depende de uma classe B
○ No código de A, existe uma referência explícita para B
○ Pode ser um acoplamento bom ou ruim
● Acoplamento evolutivo (ou lógico):
○ No código de A, não existe uma referência para B
○ Porém, mudanças em B podem impactar a classe A
51 ○ Tipo de acoplamento sempre ruim
Recomendação comum em projeto de software:
52
Exercícios
53
1. Suponha um programa em que todo o código está no método
“main”. Ele tem um problema de coesão ou acoplamento? Justifique.
2. Dê um outro exemplo de acoplamento evolutivo entre classes A e
B, semelhante ao que mostramos antes, mas que não seja baseado
em um arquivo compartilhado.
3. Ao implementar qualquer nova funcionalidade que implique na
modificação de classes A e B localizadas em arquivos diferentes, um
programador conclui a tarefa movendo as classes para o mesmo
arquivo. Ou seja: antes de terminar, ele escolhe uma das classes,
digamos B, e a move para o mesmo arquivo de A. Agindo dessa
maneira, ele estará melhorando qual propriedade de projeto? E qual
propriedade estará sendo afetada de modo negativo? Justifique.
54
4. Genericamente falando, qual dos seguintes projetos é melhor?
Justifique (nodos = módulos; arestas = dependências)
55
5. Qual dos seguintes módulos é melhor? Justifique.
50 LOC interface
57
"Diretriz" Consequência (o que
vamos ganhar
58
seguindo o princípio)
59 Figura extraída de um blog post da ThoughtWorks (link)
Princípios SOLID
Robert Martin
60
(1)Princípio da Responsabilidade Única
61
Princípios da Responsabilidade Única
● Toda classe deve ter uma única responsabilidade
● Deve existir um único motivo para modificar uma classe
62
Responsabilidade #1: calcular índice de
desistência
63
Responsabilidade #2: imprimir índice de
desistência
64
Agora versão com separação de
responsabilidades
65
66
Uma única responsabilidade: interface com o usuário
67
Uma única responsabilidade: "lógica ou regra de negócio"
68
Vantagens
● Classe de negócio (Disciplina) pode ser usada por mais
de uma classe de interface (Console, WebApp, MobileApp ...)
● Divisão de trabalho:
○ Classe de interface: frontend dev
○ Classe de negócio: backend dev
69
(2) Princípio da Segregação de Interfaces
70
Segregação de Interfaces
● Interfaces devem ser pequenas, coesas e específicas
para cada tipo de cliente
● Caso particular do princípio anterior, mas voltado para
interfaces
71
Interface genérica: trata de funcionários CLT e de
funcionários públicos
73
74
Comum para todos funcionários
75
Específica para funcionários CLT
76
Específica para funcionários públicos
77
(3) Princípio da Inversão de Dependências
78
Inversão de Dependências
● Na verdade, vamos chamar esse princípio de "Prefira
Interfaces a Classes"
● Pois transmite melhor a sua ideia!
79
80
Nos clientes, quando declarar
variáveis ou parâmetros prefira
sempre uma interface
81
Por que?
● Cliente funciona com qualquer classe que implementa I
● Isto é, com objetos das classes C1 e C2
● E também com uma nova classe (por exemplo, C3) que
venha a ser criada
82
Exemplo
83
Exemplo
84
(4) Prefira Composição a Herança
85
Contexto Histórico
● Na década de 80, quando orientação a objetos tornou-se
popular, as pessoas começaram a "abusar" de herança
● Achavam que herança iria ser uma bala de prata,
promover reúso em larga escala, etc.
86
Herança
● Relação "é-um"
● Exemplo: MotorGasolina é-um Motor
● No código:
class MotorGasolina extends Motor {
... // herda atributos e métodos de motor
87
Composição
● Relação "possui"
● Exemplo: Painel possui ContaGiros
● No código:
class Painel {
ContaGiros cg; // possui um atributo
...
}
88
Prefira Composição a Herança ⇒ não force o
uso de herança
89
Uso "forçado" de herança
Herança
90
Uso "forçado" de herança
Herança
em vez de:
Composição
91
(5) Princípio de Demeter
92
Demeter
● Demeter era o nome de um grupo de pesquisa de uma
universidade norte-americana
● Evite longas "cadeias" de chamadas de métodos
● Exemplo:
obj.getA().getB().getC().getD().getOqueEuPreciso();
objetos de passagem
93
Motivo
● Longas cadeias de chamadas quebram "encapsulamento"
● Não quero passar por A, B, C, D até obter que eu preciso
● Elos intermediários tornam a chamada frágil
94
Define quais chamadas de métodos são
"permitidas" no corpo de um método
95
96
97
98
99
Cenário não recomendado pelo Princípio de Demeter:
100 https://medium.com/@evan.hopkins.us/the-law-of-demeter-and-its-application-to-react-ab1e054f13c5
Mais um exemplo (e contra-exemplo)
101
Mas cuidado
● Demeter -- e demais princípios -- são recomendações
● Não devemos ser radicais e achar que cadeias de
chamadas de métodos são totalmente proibidas
● Casos isolados podem existir e não justificar uma
mudança no projeto
102
(6) Princípio Aberto/Fechado
103
Princípio Aberto/Fechado
● Proposto por Bertrand Meyer
● Ideia: uma classe deve estar fechada para modificações,
mas aberta para extensões
104
Explicando melhor
● Suponha que você vai implementar uma classe
● Usuários ou clientes vão querer usar a classe (óbvio!)
● Mas vão querer também customizar, parametrizar,
configurar, flexibilizar e estender a classe!
● Você deve se antecipar e tornar possível tais extensões
● Mas sem que os clientes tenham
que editar o código da classe
105
Como tornar uma classe aberta a extensões, mas
mantendo o seu código fechado para
modificações?
● Parâmetros
● Funções de mais alta ordem
● Padrões de projeto
● Herança
● etc
106
Exemplo Ordena a lista passada com parâmetro
107
Exemplo Ordena uma lista passada com parâmetro
108
Mas agora eu quero ordenar as strings da lista
pelo seu tamanho, isto é, pelo número de chars
109
Será que o método sort está aberto (preparado) para permitir
essa extensão?
110
Solução:
lista de
strings Objeto com um método compare, que
vai comparar duas strings.
Não existe almoço grátis, cliente tem
que implementar esse método
111
Resumindo: ao implementar uma classe, pense
em pontos de extensão!
112
(7) Princípio de Substituição de Liskov
113
Princípio de Substituição de Liskov
● Nome é uma referência à profa. Barbara Liskov
● Princípio define boas práticas para uso de herança
● Especificamente, boas práticas para redefinição de
métodos em subclasses
114
Primeiro: vamos entender o termo "substituição"
115
116
117
● Tipo A pode ser substituído por B1, B2, B3,...
● Desde que eles sejam subclasses de A
● Em tempo de execução, método g chamado
vai ser aquele de B1, B2, B3, etc.
118
Princípio de Substituição de Liskov
● Redefinições de métodos em subclasses são possíveis
● Mas devem preservar o contrato do método da
superclasse
● Preservar o contrato: tanto faz chamar A.g ou B1.g ou
B2.g ou B3.g
119
Para concluir, vou dar um exemplo do dia-a-dia
120
● Suponha um Médico A plantonista em um hospital
● Em um fim de semana, ele não poderá fazer seu plantão
● Então, ele pede para um colega B1 substituí-lo
● Quando a substituição vai funcionar?
○ Quando B1 tiver pelo menos a mesma competência de A
○ A substituição não vai afetar o funcionamento do hospital
○ Substituição de Liskov
121
● Quando a substituição não vai funcionar?
○ Exemplo: quando A for um Clínico Geral e B1 um Pediatra
○ Essa substituição vai prejudicar o funcionamento do
hospital
122
Fim
123