Solucionado (ver solução)
Solucionado
(ver solução)
1
resposta

Implementação sem precisar variável ou método protected

Pessoal fiz uma implementação sem precisar alterar a variável/método para protected. O que vcs acham?

package br.com.schimidtsolutions.estudo.state;

public interface EstadoOrcamento {

    public double calcularDesconto(Orcamento orcamento);

    public EstadoOrcamento aprovar();

    public EstadoOrcamento reprovar();

    public EstadoOrcamento finalizar();

    public String getNome();
}

package br.com.schimidtsolutions.estudo.state;

import java.util.Collections;
import java.util.List;
import java.util.Objects;

public class Orcamento {
    private final List<Item> itens;
    private double valor;
    private double descontos;
    private EstadoOrcamento estadoOrcamento;

    public Orcamento(final List<Item> itens) {
        Objects.requireNonNull(itens);

        estadoOrcamento = new OrcamentoEmAprovacao();
        this.itens = itens;
        recalcularValorTotal();
    }

    public List<Item> getItens() {
        return Collections.unmodifiableList(itens);
    }

    public void adicionarItem(final Item item) {
        itens.add(item);
        recalcularValorTotal();
    }

    public boolean isItemNaLista(final String nomeItem) {
        return itens.indexOf(new Item(nomeItem)) > -1;
    }

    public int getQuantidadeItens() {
        return itens.size();
    }

    public double getValorTotal() {
        return valor - descontos;
    }

    private void recalcularValorTotal() {
        valor = itens.stream().mapToDouble(Item::getValor).sum();
        descontos = 0;
    }

    public void aplicarDesconto() {
        descontos += estadoOrcamento.calcularDesconto(this);
    }

    public void aprovar() {
        estadoOrcamento = estadoOrcamento.aprovar();
    }

    public void reprovar() {
        estadoOrcamento = estadoOrcamento.reprovar();
    }

    public void finalizar() {
        estadoOrcamento = estadoOrcamento.finalizar();
    }

    @Override
    public String toString() {
        return String.format("Orcamento [itens=%s, valor=%s, estadoOrcamento=%s]", itens, getValorTotal(), getEstadoOrcamento());
    }

    public String getEstadoOrcamento() {
        return estadoOrcamento.toString();
    }
}

package br.com.schimidtsolutions.estudo.state;

public class OrcamentoAprovado implements EstadoOrcamento {
    private static final String NOME_ESTADO_ORCAMENTO = "APROVADO";

    @Override
    public double calcularDesconto(final Orcamento orcamento) {
        return orcamento.getValorTotal() * 0.02;
    }

    @Override
    public EstadoOrcamento aprovar() {
        throw new TransicaoInvalidaDeEstadoException(NOME_ESTADO_ORCAMENTO, NOME_ESTADO_ORCAMENTO);
    }

    @Override
    public EstadoOrcamento reprovar() {
        throw new TransicaoInvalidaDeEstadoException(NOME_ESTADO_ORCAMENTO, "REPROVADO");
    }

    @Override
    public EstadoOrcamento finalizar() {
        return new OrcamentoFinalizado();
    }

    @Override
    public String toString() {
        return getNome();
    }

    @Override
    public String getNome() {
        return NOME_ESTADO_ORCAMENTO;
    }
}

package br.com.schimidtsolutions.estudo.state;

public class OrcamentoEmAprovacao implements EstadoOrcamento {
    private static final String NOME_ESTADO_ORCAMENTO = "EM APROVAÇÃO";

    @Override
    public double calcularDesconto(final Orcamento orcamento) {
        return orcamento.getValorTotal() * 0.05;
    }

    @Override
    public EstadoOrcamento aprovar() {
        return new OrcamentoAprovado();
    }

    @Override
    public EstadoOrcamento reprovar() {
        return new OrcamentoReprovado();
    }

    @Override
    public EstadoOrcamento finalizar() {
        throw new TransicaoInvalidaDeEstadoException(NOME_ESTADO_ORCAMENTO, "FINALIZADO");
    }

    @Override
    public String toString() {
        return getNome();
    }

    @Override
    public String getNome() {
        return NOME_ESTADO_ORCAMENTO;
    }
}

package br.com.schimidtsolutions.estudo.state;

public class OrcamentoFinalizado implements EstadoOrcamento {
    private static final String NOME_ESTADO_ORCAMENTO = "FINALIZADO";

    @Override
    public double calcularDesconto(final Orcamento orcamento) {
        throw new DescontoInvalidoException(NOME_ESTADO_ORCAMENTO);
    }

    @Override
    public EstadoOrcamento aprovar() {
        throw new TransicaoInvalidaDeEstadoException(NOME_ESTADO_ORCAMENTO, "APROVADO");
    }

    @Override
    public EstadoOrcamento reprovar() {
        throw new TransicaoInvalidaDeEstadoException(NOME_ESTADO_ORCAMENTO, "REPROVADO");
    }

    @Override
    public EstadoOrcamento finalizar() {
        throw new TransicaoInvalidaDeEstadoException(NOME_ESTADO_ORCAMENTO, "FINALIZADO");
    }

    @Override
    public String toString() {
        return getNome();
    }

    @Override
    public String getNome() {
        return NOME_ESTADO_ORCAMENTO;
    }
}

package br.com.schimidtsolutions.estudo.state;

public class OrcamentoReprovado implements EstadoOrcamento {
    private static final String NOME_ESTADO_ORCAMENTO = "REPROVADO";

    @Override
    public double calcularDesconto(final Orcamento orcamento) {
        throw new DescontoInvalidoException(NOME_ESTADO_ORCAMENTO);
    }

    @Override
    public EstadoOrcamento aprovar() {
        throw new TransicaoInvalidaDeEstadoException(NOME_ESTADO_ORCAMENTO, "APROVADO");
    }

    @Override
    public EstadoOrcamento reprovar() {
        throw new TransicaoInvalidaDeEstadoException(NOME_ESTADO_ORCAMENTO, NOME_ESTADO_ORCAMENTO);
    }

    @Override
    public EstadoOrcamento finalizar() {
        return new OrcamentoFinalizado();
    }

    @Override
    public String toString() {
        return getNome();
    }

    @Override
    public String getNome() {
        return NOME_ESTADO_ORCAMENTO;
    }
}

package br.com.schimidtsolutions.estudo.state;

import com.google.common.collect.Lists;

public class TesteEstadoOrcamento {

    public static void main(final String[] args) {
        Orcamento orcamento = new Orcamento(Lists.newArrayList(new Item("CANETA", 250), new Item("CANETA", 250)));

        orcamento.aplicarDesconto();

        System.out.println(orcamento);

        orcamento.aprovar();

        orcamento.aplicarDesconto();

        System.out.println(orcamento);

        orcamento.finalizar();

        System.out.println(orcamento);
    }
}

package br.com.schimidtsolutions.estudo.state;

public class DescontoInvalidoException extends RuntimeException {
    private static final long serialVersionUID = 1L;

    public DescontoInvalidoException(final String estadoInvalidoOrcamentoParaDesconto) {
        super(String.format("Não é possivel aplicar desconto para um orçamento %s!", estadoInvalidoOrcamentoParaDesconto));
    }
}

package br.com.schimidtsolutions.estudo.state;

public class TransicaoInvalidaDeEstadoException extends RuntimeException {
    private static final long serialVersionUID = 1L;

    public TransicaoInvalidaDeEstadoException(final String estadoAtual, final String estadoInvalido) {
        super(String.format("Não é possível o orçamento passar do estado de %s para %s!", estadoAtual, estadoInvalido));
    }
}
1 resposta
solução!

Excelente! Felipe, dá muito orgulho ver alunos que vão longe assim em exercícios. E é sempre mais " elegante" usar as interfaces em vez das classes abstratas com protected, apesar de hoje em dia eu ser mais pragmático