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));
}
}