Escolar Documentos
Profissional Documentos
Cultura Documentos
LIVRO 03
Padrões SOLID
Sumário
1. Padrões SOLID
2. Básico
S Single Responsability Principle (Princípio da responsabilidade única)
3. Intermediário
O Openclosed Principle (Princípio Abertofechado)
L Liskov Substitution Principle (Princípio da Substituição de Liskov)
4. Avançado
I Interface Segregation Principle (Princípio da Segregação da Interface)
D Dependency Inversion Principle (Princípio da inversão da Dependência)
5. Referências
Padrões SOLID
O SOLID é uma junção de princípios e boas práticas que visam melhorar um projeto, facilitando
sua manutenção e compreensão.
O termo SOLID surgiu após seu criador, Michael Feathers, observar que era possível unificar os
cinco princípios da orientação a objeto na sigla SOLID.
Esses princípios ajudam os desenvolvedores a melhorarem seu código, separando
responsabilidades, tornando o código mais limpo e consequentemente mais legível, facilitando a
manutenção, o reaproveitamento de trechos de códigos entre muitos outros benefícios.
Os padrões SOLID se baseiam nos quatro principais pilares da programação POO:
Abstração
Encapsulamento
Polimorfismo
Herança
1 2 3 4 5 6 7 8 9 10
S Responsabilidade Única Caso de Uso
Caso de Uso
Temos um projeto aonde uma classe chamada CozinheiroFazTudo possui três métodos para manipular a classe Prato:
fazerPrato, valorDoPrato e recolherPratos.
Esta não é a situação ideal, portanto vamos implementar o padrão S, de Responsabilidade Única.
Neste padrão, uma classe deve ter um, e somente um, motivo para atuar. Esse princípio declara que uma classe deve
ser especializada em um único assunto e possuir apenas uma responsabilidade dentro do software, ou seja, a classe
deve ter uma única tarefa ou ação para executar.
1 2 3 4 5 6 7 8 9 10
Diagrama
S Responsabilidade Única Conceitual
antes depois
faz
cobra faz cobra recolhe
recolhe
Prato Prato
nome nome
ingredientes ingredientes
preço preço
1 2 3 4 5 6 7 8 9 10
S Responsabilidade Única Implementação
Passo 1: implemente a classe Prato Passo 2: implemente a classe CozinheiroFazTudo
Esta classe será manipulada pelas outras classes. Esta classe vai ser responsável por todas as
operações sobre a classe Prato.
package srp;
package srp;
import java.util.List;
public class CozinheiroFazTudo {
public class Prato { String nome;
private String nome;
private List<String> ingredientes; public CozinheiroFazTudo(String nome) {
private double valor; System.out.println("========Cozinheiro que faz tudo - " + nome + "========");
this.nome = nome;
public Prato(String nome, List<String> ingredientes, double valor) { }
this.nome = nome;
this.ingredientes = ingredientes; public void fazerPrato(Prato prato) {
this.valor = valor; System.out.println("Fazendo prato " + prato.getNome());
} }
public String getNome() { return nome; } public double valorDoPrato(Prato prato) {
public List<String> getIngredientes() { return ingredientes; } return prato.getValor();
public double getValor() { return valor; } }
public void setNome(String nome) { this.nome = nome; } public void recolherPratos() {
public void setIngredientes(List<String> ingredientes){this.ingredientes = ingredientes; } System.out.println("Recolhendo pratos...");
public void setValor(double valor) { this.valor = valor; } }
} }
1 2 3 4 5 6 7 8 9 10
S Responsabilidade Única Implementação
Passo 3: implemente a classe Cozinheiro Passo 4: implemente a classe Caixa
Esta classe vai ser responsável apenas por fazer o Esta classe vai ser responsável apenas por calcular
Prato. o valor do Prato.
1 2 3 4 5 6 7 8 9 10
S Responsabilidade Única Implementação
Passo 5: implemente a classe Garçom Passo 6: implemente a classe TesteErrado
Esta classe vai ser responsável apenas por rescolher Esta classe vai executar a situação antes da
os Pratos. implementação do padrão.
package srp;
package srp; import java.util.ArrayList;
public class Garçom { import java.util.List;
String nome; public class TesteErrado {
public Garçom(String nome) { public static void main(String[] args) {
System.out.println("\n========Cozinheiro especializado em recolher prato - " + List<String> ingredientesPrato1 = new ArrayList<String>();
nome + "========"); ingredientesPrato1 .add("Costela de porco");
this.nome = nome; ingredientesPrato1 .add("Linguiça");
} ingredientesPrato1 .add("Bacon");
public void recolherPratos() { ingredientesPrato1 .add("Feijão preto");;
System.out.println("Recolhendo pratos..."); Prato p1 = new Prato("Feijoada", ingredientesPrato1 , 29.99);
}
}
CozinheiroFazTudo cozinheiro = new CozinheiroFazTudo("Roberto");
cozinheiro.fazerPrato(p1 );
System.out.println("Valor do prato: " + cozinheiro.valorDoPrato(p1 ));
cozinheiro.recolherPratos();
}
}
1 2 3 4 5 6 7 8 9 10
S Responsabilidade Única Implementação
Passo 7: implemente a classe TesteCerto
package srp;
Esta classe vai executar a situação depois da import java.util.ArrayList;
implementação do padrão. public class TesteCerto {
Neste padrão, cada classe tem sua public static void main(String[] args) {
responsabilidade: o cozinheiro faz o prato, o caixa ArrayList<String> ingredientesPrato1 = new ArrayList<String>();
ingredientesPrato1 .add("Costela de porco");
define o valor do prato, o garçom recolhe os pratos. ingredientesPrato1 .add("Linguiça");
ingredientesPrato1 .add("Bacon");
ingredientesPrato1 .add("Feijão preto");
ingredientesPrato1 .add("Cebola");
ingredientesPrato1 .add("Alho");
ingredientesPrato1 .add("Sal");;
Prato p1 = new Prato("Feijoada", ingredientesPrato1 , 29.99);
Cozinheiro cozinheiro = new Cozinheiro("Felipe");
cozinheiro.fazerPrato(p1 );
Caixa caixa = new Caixa("Casemiro");
System.out.println("Valor do prato: " + caixa.valorDoPrato(p1 ));
Garçom garçom = new Garçom("Gustavo");
garçom.recolherPratos();
}
}
1 2 3 4 5 6 7 8 9 10
O Abertofechado Caso de Uso e
Diagrama Conceitual
Diagrama Conceitual
Caso de Uso
A classe Cubo está pronta, tem seus atributos e
métodos definidos. Aplicação
volumeTotal
Precisamos implementar o calculo do volume do
cubo.
1 2 3 4 5 6 7 8 9 10
O Abertofechado Implementação
Passo 1: implemente a classe Cubo Passo 2: implemente a classe Aplicação
Esta classe define o cubo que não será alterada no Esta classe vai extender a funcionalidade do cubo,
futuro, vamos criar uma aplicação. sem alteralo
1 2 3 4 5 6 7 8 9 10
O Abertofechado Implementação
Passo 3: implemente a classe que executa
//Declaracao de uma array que vai receber os dados dos cubos
Cubo[] arrayCubo = new Cubo[3];
Esta classe vai executar a aplicação, que vai arrayCubo[0] = cb1 ;
extender a funcionalidade do cubo. arrayCubo[1 ] = cb2;
arrayCubo[2] = cb3;
//Inicializo a classe aplicacao
package exemploocp; Aplicacao app = new Aplicacao();
/* //Envia para a classe aplicacao o arrayCubo e recebe o volume total
Classe principal , Nela vai conter a declaracao do cubo e a insercao de dados double volume = app.volumeTotal(arrayCubo);
*/
// Print and Display the Total Volume
public class ExemploOCP { System.out.println("O volume total de todos os cubos eh " + volume);
public static void main(String[] args) {
}
//inicializando os cubos }
Cubo cb1 = new Cubo();
Cubo cb2 = new Cubo();
Cubo cb3 = new Cubo();
//inserindo os dados dos cubos
cb1 .comprimento = 5; cb1 .largura = 1 0; cb1 .altura = 1 5;
cb2.comprimento = 2; cb2.largura = 4; cb2.altura = 6;
cb3.comprimento = 3; cb3.largura = 1 2; cb3.altura = 1 5;
1 2 3 4 5 6 7 8 9 10
L Substituição de Liskov Caso de Uso
Caso de Uso
O Princípio de Substituição de Liskov afirma que os objetos de uma superclasse devem ser substituídos por objetos de
suas subclasses sem quebrar o aplicativo.
Em outras palavras, o que queremos é que os objetos de nossas subclasses se comportem da mesma forma que os
objetos de nossa superclasse.
1 2 3 4 5 6 7 8 9 10
L Substituição de Liskov Diagrama Conceitual
A ser implementado pelos alunos.
1 2 3 4 5 6 7 8 9 10
L Substituição de Liskov Implementação
1 2 3 4 5 6 7 8 9 10
I Segregação da Interface Caso de Uso
Esse padrão de projetos diz que cada classe deve possuir uma única responsabilidade. Desse modo o código torna
se mais claro e reutilizável. A desvantagem é que teremos um número de classes maior que teríamos sem o padrão. A
alta coesão significa que cada classe terá suas responsabilidades altamente focadas.
Neste caso, temos uma interface que implementar as ações de nadar, correr e arremessar. a classe Atleta contrata a
interface AtletaAcoes, e isso vai obrigar a classe Atleta a implementar todas as três ações.
Seguindo o padrão de segregação da interface, vamos criar três interfaces distintas, uma para cada ação. Isso
permitirá que o classe atleta contrate apenas a interface que lhe interessa.
1 2 3 4 5 6 7 8 9 10
I Segregação da Interface Diagrama
Conceitual
antes depois
Atleta Atleta
1 2 3 4 5 6 7 8 9 10
I Segregação da Interface Implementação
1 2 3 4 5 6 7 8 9 10
I Segregação da Interface Implementação
package ISPExample;
public interface AtletaNatacao {
void nadar();
}
1 2 3 4 5 6 7 8 9 10
D Inversão da dependência Caso de Uso e
Diagrama Conceitual
Caso de Uso
As classes devem depender de abstrações e não de coisas concretas.
A ideia é: sempre que uma classe for depender de outra, ela deve depender sempre de outro módulo mais estável do
que ela mesma. Se A depende de B, a ideia é que B seja mais estável que A. Mas B depende de C. Logo, a ideia é
que C seja mais estável que B.
Ou seja, suas classes devem sempre andar em direção à estabilidade, depender de módulos mais estáveis que ela
própria.
Mas como conseguir isso? Lembrese que abstrações tendem a ser estáveis, e implementações instáveis. Se você está
programando alguma classe qualquer com regras de negócio, e precisa depender de outro módulo, idealmente
esse outro módulo deve ser uma abstração. Tente ao máximo não depender de outras implementações (afinal, elas
são instáveis).
1 2 3 4 5 6 7 8 9 10
D Inversão da dependência Implementação
1 2 3 4 5 6 7 8 9 10
Referências
Orientação a Objetos e SOLID para Ninjas Maurício Aniche
Pesquisa Single Responsability Daniel Borba Guimães da Costa / Thais Resende Araújo Borges
Bonfim
Pesquisa Openclosed, Interface Segregation David Gabriel B. Jorge / Murillo Sampaio
Oliveira Antonio
1 2 3 4 5 6 7 8 9 10
Só mais uma coisa...
@laertecoutinho1