Srp
Ocp
Lsp
Isp
Dip
SRP - Single Responsibility Principle
public class CalculadoraDeSalario {
public double calcula(Funcionario funcionario) {
if(DESENVOLVEDOR.equals(funcionario.getCargo())) {
return dezOuVintePorCento(funcionario);
}
if (DBA.equals(funcionario.getCargo()) ||
TESTER.equals(funcionario.getCargo())) {
return quinzeOuVinteCincoPorCento(funcionario);
}
throw new RuntimeException("Funcionário Inválido");
}
private double quinzeOuVinteCincoPorCento(Funcionario funcionario) {
if(funcionario.getSalarioBase() > 2000) {
return funcionario.getSalarioBase() * 0.75;
} else {
return funcionario.getSalarioBase() * 0.85;
}
}
private double dezOuVintePorCento(Funcionario funcionario) {
if(funcionario.getSalarioBase() > 3000) {
return funcionario.getSalarioBase() * 0.8;
} else {
return funcionario.getSalarioBase() * 0.9;
}
}
}
public class CalculadoraDeSalario
(m) double calcula(Funcionario)
public class Funcionario
// mais campos
(f) Cargo cargo;
(f) double salarioBase;
(m) double calculaSalario;
public enum Cargo {
DESENVOLVEDOR(new DezOuVintePorCento()),
DBA(new QuinzeOuVinteCincoPorCento()),
TESTER(new QuinzeOuVinteCincoPorCento());
(f) RegraDeCalculo regra;
(c) Cargo(RegraDeCalculo regra) this.regra = regra;
(m) RegraDeCalculo getRegra
public interface RegraDeCalculo
(m) double calcula(Funcionario)
public double calculaSalario() {
return cargo.getRegra().calcula(this);
}
OCP - Open/Closed Principle
- Aberta para extensão
- Fechada para modificação
LSP - Liskov Substitutive Principle
- Classes derivadas devem ser substituíveis por suas
classes bases
- Deve-se pensar muito nas pré-condições e pós-condições
ISP - Interface Segregation Principle
- Clientes não devem ser forçados a depender de métodos
que não usam
DIP - Dependency Inversion Principle
- Dependa sempre de abstração, não de implementação
Don’t repeat yourself - Não repetir código, movendo partes
que precisam ser reutilizadas para métodos ou classes.
WET -
“Write Everything Twice”
“We Enjoy Typing”
“Waste Everyone’s Time”
DRY
KISS
Keep It Simple, Stupid
private static String semana(int dia) {
switch (dia){
case 1:
return "Segunda-feira";
case 2:
return "Terça-feira";
case 3:
return "Quarta-feira";
case 4:
return "Quinta-feira";
case 5:
return "Sexta-feira";
case 6:
return "Sabado";
case 7:
return "Domingo";
default:
throw new IllegalArgumentException("Dia
inválido: Somente números entre 1 e 7");
}
}
private static String semana(int dia) {
if(dia < 1 || dia > 7) throw new
IllegalArgumentException("Dia inválido: Somente
números entre 1 e 7");
String[] diasDaSemana = {
"Segunda-feira",
"Terça-feira",
"Quarta-feira",
"Quinta-feira",
"Sexta-feira",
"Sábado",
"Domingo"
};
return diasDaSemana[dia - 1];
}
API Best Practices
1) HTTP aplicado a REST
- Conhecer bem a base
2) Não retorne texto puro
- Passar o content-type!
3) Evite usar verbos nas URIs
- Metodos HTTP devem ser suficiente para
descrever a ação
4) Use plurais nos recursos
- É preferível o uso de plurais para garantir a
padronização
GET /loja/listaClientes/
GET /loja/clientes/
GET /loja/cliente/1
GET /loja/clientes/
GET /loja/clientes/
POST /loja/clientes/
5) Retorne detalhes dos erros no body
- Retornar detalhes de erros ajuda a fazer o
debug
6) Retorne StatusCodes significativos
{
“error” : “Email inválido”
“detail” : {
“surname” :
“...”
}
}
HTTP/1.1 200 OK
Content-Type: text/html
{
"status": "failure",
"data": {
"error": "Nome é obrigatório"
}
}
7) Use StatusCode consistentemente
- Use um padrão
- Retorne sempre o mesmo StatusCode para
aquele tipo de requisição
8) Evite Nested Resources
- Pode ficar confuso
- Prefira QueryParams
GET /pacientes/5/prontuario
GET /prontuarios/?paciente_id=5
9) Lide com barras finais 10) Use QueryParams para filtros e paginação
POST /pacientes
POST /pacientes/
GET /artigos/?page=8&size=10
GET /artigos/revisados
GET /artigos/?revisados=true&page=5&size=10
Style Guide - Java
Um conjunto de regras para padronizar a escrita do código,
regendo desde a identação do código até a criação do Javadoc
Algumas regras
Segundo o Google JavaStryleGuide: https://google.github.io/styleguide/javaguide.html
- Estrutura do arquivo-fonte;
- Caracteres especiais
- Formatação;
- Nomenclatura;
Design Patterns
Strategy
- Separa os algoritmos para alcançar a reusabilidade
- Permite selecionar um algoritmo durante a execução
Contexto
<<interface>>
Estratégia
+executa()
Estratégia
1
+executa()
Estratégia
2
+executa()
public class CalculadoraDeImpostos {
public void realizaCalculo(Orcamento orcamento, String imposto) {
if(imposto.equals("ICMS")) System.out.println(orcamento.getValor() * 0.1);
else if (imposto.equals("ISS")) System.out.println(orcamento.getValor() * 0.06);
// else if mais um
// else if e outro
// else if continua crescendo
// else if não para
}
}
public class CalculadoraDeImpostos {
public void realizaCalculoICMS(Orcamento orcamento) {
System.out.println(new ICMS().calculaICMS(orcamento));
}
public void realizaCalculoISS(Orcamento orcamento) {
System.out.println(new ISS().calculaISS(orcamento));
}
// E mais um método
// E outro
// E aqui mais um
}
public class CalculadoraDeImpostos {
public void realizaCalculo(Orcamento orcamento, Imposto
imposto) {
System.out.println(imposto.calcula(orcamento));
}
}
public interface Imposto {
double calcula(Orcamento orcamento);
}
public class ICMS implements Imposto {
@Override
public double calcula(Orcamento orcamento) {
return orcamento.getValor() * 0.1;
}
}
public class ISS implements Imposto {
@Override
public double calcula(Orcamento orcamento) {
return orcamento.getValor() * 0.06;
}
}
public class TesteCalculadora {
public static void main(String[] args) {
Orcamento orcamento = new Orcamento(500);
var calculadora = new CalculadoraDeImpostos();
System.out.println("******* ICMS *********");
calculadora.realizaCalculo(orcamento, new ICMS());
System.out.println("******* ISS *********");
calculadora.realizaCalculo(orcamento, new ISS());
}
}
State
- Permite alterar o comportamento baseado no estado interno do objeto
<<interface>>
Estado
+acao1()
+ação2()
Estado 1
+acao1()
+acao2()
Estado 2
+acao1()
+acao2()
Contexto
+metodo()
estado;
public class Orcamento {
private double valor;
private List<Item> itens;
public Orcamento(double valor) {
this.valor = valor;
this.itens = new ArrayList<Item>();
}
public double getValor() { return valor; }
public void desconta(double valor) {
this.valor -= valor;
}
public List<Item> getItens() {
return Collections.unmodifiableList(itens);
}
public void adicionaItem(Item item) {
itens.add(item);
}
}
public class Orcamento {
public static final int EM_APROVACAO = 1;
public static final int APROVADO = 2;
public static final int REPROVADO = 3;
public static final int FINALIZADO = 4;
private double valor;
private List<Item> itens;
private int estadoAtual;
// resto da classe escondida porque não cabia mais na tela
public void aplicaDescontoExtra() {
if(estadoAtual == EM_APROVACAO) valor = valor - (valor * 0.05);
else if(estadoAtual == APROVADO) valor = valor - (valor * 0.02);
else throw new RuntimeException("Orçamentos reprovados não
recebem desconto extra!");
}
}
public class Orcamento {
private double valor;
private List<Item> itens;
private EstadoAtualDeUmOrcamento estadoAtual;
public Orcamento(double valor) {
this.valor = valor;
this.itens = new ArrayList<Item>();
this.estadoAtual = new EmAprovacao();
}
// resto da classe porque não cabia mais na tela
public void aplicaDescontoExtra() {
estadoAtual.aplicaDescontoExtra(this);
}
}
Em Aprovação
Aprovado Reprovado
Finalizado
public class Orcamento {
// resto da classe porque não cabia mais na tela
public void
alteraEstado(EstadoAtualDeUmOrcamento
novoEstado) {
this.estadoAtual = novoEstado;
}
public void aprova() {
estadoAtual.aprova(this);
}
public void reprova() {
estadoAtual.reprova(this);
}
public void finaliza() {
estadoAtual.finaliza(this);
}
}
public interface EstadoAtualDeUmOrcamento {
void aplicaDescontoExtra(Orcamento orcamento);
void aprova(Orcamento orcamento);
void reprova(Orcamento orcamento);
void finaliza(Orcamento orcamento);
}
public class EmAprovacao implements EstadoAtualDeUmOrcamento {
@Override
public void aplicaDescontoExtra(Orcamento orcamento) {
orcamento.desconta(orcamento.getValor() * 0.05); }
@Override
public void aprova(Orcamento orcamento) {
orcamento.alteraEstado(new Aprovado()); }
@Override
public void reprova(Orcamento orcamento) {
orcamento.alteraEstado(new Reprovado());}
@Override
public void finaliza(Orcamento orcamento) {
throw new IllegalStateException("Orçamentos em aprovação não
podem ser finalizados"); }
}

Design patterns

  • 1.
  • 2.
    SRP - SingleResponsibility Principle
  • 3.
    public class CalculadoraDeSalario{ public double calcula(Funcionario funcionario) { if(DESENVOLVEDOR.equals(funcionario.getCargo())) { return dezOuVintePorCento(funcionario); } if (DBA.equals(funcionario.getCargo()) || TESTER.equals(funcionario.getCargo())) { return quinzeOuVinteCincoPorCento(funcionario); } throw new RuntimeException("Funcionário Inválido"); } private double quinzeOuVinteCincoPorCento(Funcionario funcionario) { if(funcionario.getSalarioBase() > 2000) { return funcionario.getSalarioBase() * 0.75; } else { return funcionario.getSalarioBase() * 0.85; } } private double dezOuVintePorCento(Funcionario funcionario) { if(funcionario.getSalarioBase() > 3000) { return funcionario.getSalarioBase() * 0.8; } else { return funcionario.getSalarioBase() * 0.9; } } }
  • 4.
    public class CalculadoraDeSalario (m)double calcula(Funcionario) public class Funcionario // mais campos (f) Cargo cargo; (f) double salarioBase; (m) double calculaSalario; public enum Cargo { DESENVOLVEDOR(new DezOuVintePorCento()), DBA(new QuinzeOuVinteCincoPorCento()), TESTER(new QuinzeOuVinteCincoPorCento()); (f) RegraDeCalculo regra; (c) Cargo(RegraDeCalculo regra) this.regra = regra; (m) RegraDeCalculo getRegra public interface RegraDeCalculo (m) double calcula(Funcionario) public double calculaSalario() { return cargo.getRegra().calcula(this); }
  • 5.
    OCP - Open/ClosedPrinciple - Aberta para extensão - Fechada para modificação
  • 6.
    LSP - LiskovSubstitutive Principle - Classes derivadas devem ser substituíveis por suas classes bases - Deve-se pensar muito nas pré-condições e pós-condições
  • 7.
    ISP - InterfaceSegregation Principle - Clientes não devem ser forçados a depender de métodos que não usam
  • 8.
    DIP - DependencyInversion Principle - Dependa sempre de abstração, não de implementação
  • 9.
    Don’t repeat yourself- Não repetir código, movendo partes que precisam ser reutilizadas para métodos ou classes. WET - “Write Everything Twice” “We Enjoy Typing” “Waste Everyone’s Time” DRY
  • 10.
  • 11.
    private static Stringsemana(int dia) { switch (dia){ case 1: return "Segunda-feira"; case 2: return "Terça-feira"; case 3: return "Quarta-feira"; case 4: return "Quinta-feira"; case 5: return "Sexta-feira"; case 6: return "Sabado"; case 7: return "Domingo"; default: throw new IllegalArgumentException("Dia inválido: Somente números entre 1 e 7"); } } private static String semana(int dia) { if(dia < 1 || dia > 7) throw new IllegalArgumentException("Dia inválido: Somente números entre 1 e 7"); String[] diasDaSemana = { "Segunda-feira", "Terça-feira", "Quarta-feira", "Quinta-feira", "Sexta-feira", "Sábado", "Domingo" }; return diasDaSemana[dia - 1]; }
  • 12.
    API Best Practices 1)HTTP aplicado a REST - Conhecer bem a base 2) Não retorne texto puro - Passar o content-type!
  • 13.
    3) Evite usarverbos nas URIs - Metodos HTTP devem ser suficiente para descrever a ação 4) Use plurais nos recursos - É preferível o uso de plurais para garantir a padronização GET /loja/listaClientes/ GET /loja/clientes/ GET /loja/cliente/1 GET /loja/clientes/ GET /loja/clientes/ POST /loja/clientes/
  • 14.
    5) Retorne detalhesdos erros no body - Retornar detalhes de erros ajuda a fazer o debug 6) Retorne StatusCodes significativos { “error” : “Email inválido” “detail” : { “surname” : “...” } } HTTP/1.1 200 OK Content-Type: text/html { "status": "failure", "data": { "error": "Nome é obrigatório" } }
  • 15.
    7) Use StatusCodeconsistentemente - Use um padrão - Retorne sempre o mesmo StatusCode para aquele tipo de requisição 8) Evite Nested Resources - Pode ficar confuso - Prefira QueryParams GET /pacientes/5/prontuario GET /prontuarios/?paciente_id=5
  • 16.
    9) Lide combarras finais 10) Use QueryParams para filtros e paginação POST /pacientes POST /pacientes/ GET /artigos/?page=8&size=10 GET /artigos/revisados GET /artigos/?revisados=true&page=5&size=10
  • 17.
    Style Guide -Java Um conjunto de regras para padronizar a escrita do código, regendo desde a identação do código até a criação do Javadoc
  • 18.
    Algumas regras Segundo oGoogle JavaStryleGuide: https://google.github.io/styleguide/javaguide.html - Estrutura do arquivo-fonte; - Caracteres especiais - Formatação; - Nomenclatura;
  • 19.
  • 20.
    Strategy - Separa osalgoritmos para alcançar a reusabilidade - Permite selecionar um algoritmo durante a execução Contexto <<interface>> Estratégia +executa() Estratégia 1 +executa() Estratégia 2 +executa()
  • 21.
    public class CalculadoraDeImpostos{ public void realizaCalculo(Orcamento orcamento, String imposto) { if(imposto.equals("ICMS")) System.out.println(orcamento.getValor() * 0.1); else if (imposto.equals("ISS")) System.out.println(orcamento.getValor() * 0.06); // else if mais um // else if e outro // else if continua crescendo // else if não para } }
  • 22.
    public class CalculadoraDeImpostos{ public void realizaCalculoICMS(Orcamento orcamento) { System.out.println(new ICMS().calculaICMS(orcamento)); } public void realizaCalculoISS(Orcamento orcamento) { System.out.println(new ISS().calculaISS(orcamento)); } // E mais um método // E outro // E aqui mais um }
  • 23.
    public class CalculadoraDeImpostos{ public void realizaCalculo(Orcamento orcamento, Imposto imposto) { System.out.println(imposto.calcula(orcamento)); } } public interface Imposto { double calcula(Orcamento orcamento); } public class ICMS implements Imposto { @Override public double calcula(Orcamento orcamento) { return orcamento.getValor() * 0.1; } } public class ISS implements Imposto { @Override public double calcula(Orcamento orcamento) { return orcamento.getValor() * 0.06; } } public class TesteCalculadora { public static void main(String[] args) { Orcamento orcamento = new Orcamento(500); var calculadora = new CalculadoraDeImpostos(); System.out.println("******* ICMS *********"); calculadora.realizaCalculo(orcamento, new ICMS()); System.out.println("******* ISS *********"); calculadora.realizaCalculo(orcamento, new ISS()); } }
  • 24.
    State - Permite alteraro comportamento baseado no estado interno do objeto <<interface>> Estado +acao1() +ação2() Estado 1 +acao1() +acao2() Estado 2 +acao1() +acao2() Contexto +metodo() estado;
  • 25.
    public class Orcamento{ private double valor; private List<Item> itens; public Orcamento(double valor) { this.valor = valor; this.itens = new ArrayList<Item>(); } public double getValor() { return valor; } public void desconta(double valor) { this.valor -= valor; } public List<Item> getItens() { return Collections.unmodifiableList(itens); } public void adicionaItem(Item item) { itens.add(item); } } public class Orcamento { public static final int EM_APROVACAO = 1; public static final int APROVADO = 2; public static final int REPROVADO = 3; public static final int FINALIZADO = 4; private double valor; private List<Item> itens; private int estadoAtual; // resto da classe escondida porque não cabia mais na tela public void aplicaDescontoExtra() { if(estadoAtual == EM_APROVACAO) valor = valor - (valor * 0.05); else if(estadoAtual == APROVADO) valor = valor - (valor * 0.02); else throw new RuntimeException("Orçamentos reprovados não recebem desconto extra!"); } }
  • 26.
    public class Orcamento{ private double valor; private List<Item> itens; private EstadoAtualDeUmOrcamento estadoAtual; public Orcamento(double valor) { this.valor = valor; this.itens = new ArrayList<Item>(); this.estadoAtual = new EmAprovacao(); } // resto da classe porque não cabia mais na tela public void aplicaDescontoExtra() { estadoAtual.aplicaDescontoExtra(this); } } Em Aprovação Aprovado Reprovado Finalizado
  • 27.
    public class Orcamento{ // resto da classe porque não cabia mais na tela public void alteraEstado(EstadoAtualDeUmOrcamento novoEstado) { this.estadoAtual = novoEstado; } public void aprova() { estadoAtual.aprova(this); } public void reprova() { estadoAtual.reprova(this); } public void finaliza() { estadoAtual.finaliza(this); } } public interface EstadoAtualDeUmOrcamento { void aplicaDescontoExtra(Orcamento orcamento); void aprova(Orcamento orcamento); void reprova(Orcamento orcamento); void finaliza(Orcamento orcamento); } public class EmAprovacao implements EstadoAtualDeUmOrcamento { @Override public void aplicaDescontoExtra(Orcamento orcamento) { orcamento.desconta(orcamento.getValor() * 0.05); } @Override public void aprova(Orcamento orcamento) { orcamento.alteraEstado(new Aprovado()); } @Override public void reprova(Orcamento orcamento) { orcamento.alteraEstado(new Reprovado());} @Override public void finaliza(Orcamento orcamento) { throw new IllegalStateException("Orçamentos em aprovação não podem ser finalizados"); } }