Solucionado (ver solução)
Solucionado
(ver solução)
4
respostas

Dúvida no Ex. 4 da Aula 2 - Acoplamento e a estabilidade

Olá,

Gostei de como o acoplamento diminuiu na classe GeradorDeNotaFiscal: vi que, basicamente, vocês trocaram a dependência de duas classes (EnviadorDeEmail e NotaFiscalDao) por uma interface mais estável (AcaoAposGerarNota). Embora tenha adicionado complexidade, adotando um observer...

Minha dúvida é: pra mim, GeradorDeNotaFiscal ainda tem um problema com coesão. Ele faz mais do que gerar nota fiscal, ele é também responsável por ações após a geração da nf (AcaoAposGerarNota). Faz sentido? Eu teria que tentar separar um pouco mais essas responsabilidades? É possível melhorar ainda mais a coesão e acoplamento nesse exemplo?

4 respostas
solução!

Boa pergunta Igor!

GeradorDeNotaFiscal está acoplado à NotaFiscal, tendo a responsabilidade de controlar o ciclo de vida desta.

Eu faria da seguinte forma...

Colocaria o método de gerar nota fiscal dentro da classe Fatura passando como argumento as ações que devem ser realizadas após gerar a NotaFiscal, já que a NotaFiscal depende dos dados da Fatura para ser gerada. Também criaria uma interface Imposto com o método calcular(), depois criaria uma classe ImpostoSimples que implementa a interface Imposto. Esta interface seria o tipo da minha propriedade imposto, com isto, o calculo de imposto da fatura poderia ser alterado para qualquer tipo de imposto, alterando apenas o implementação do imposto que eu quero calcular:

import java.util.List;

public class Fatura {

    private double valorMensal;
    private String cliente;
    private Imposto imposto;

    public Fatura(double valorMensal, String cliente, Imposto imposto) {
        this.valorMensal = valorMensal;
        this.cliente = cliente;
        this.imposto = imposto;
    }

    public double getValorMensal() {
        return valorMensal;
    }

    public void setValorMensal(double valorMensal) {
        this.valorMensal = valorMensal;
    }

    public String getCliente() {
        return cliente;
    }

    public void setCliente(String cliente) {
        this.cliente = cliente;
    }

    public Imposto getImposto() {
        return imposto;
    }

    public void setImposto(Imposto imposto) {
        this.imposto = imposto;
    }

    public NotaFiscal gerarNotaFiscal(List<AcaoPosNotaFiscal> acoesPosNotaFiscal) {
        return new NotaFiscal(this.valorMensal, this.getValorImposto(), acoesPosNotaFiscal);
    }

    private double getValorImposto() {
        return this.imposto.calcular(this.valorMensal);
    }
}

public interface Imposto {
    public double calcular(double valor);
}

public class ImpostoSimples implements Imposto {

    public double calcular(double valor) {
        return valor * 0.06;
    }
}

Na classe NotaFiscal eu coloquei a lista com as ações que devem ser executadas após gerar a nota, como propriedade da classe. Também criei um método privado que executa estas ações e é chamado no construtor logo após settar os valores nas propriedades:

import java.util.List;

public class NotaFiscal {

    private int id;
    private double valorBruto;
    private double impostos;
    private final List<AcaoPosNotaFiscal> acoesPosNotaFiscal;

    public NotaFiscal(int id, double valorBruto, double impostos, List<AcaoPosNotaFiscal> acoesPosNotaFiscal) {
        this.id = id;
        this.valorBruto = valorBruto;
        this.impostos = impostos;
        this.acoesPosNotaFiscal = acoesPosNotaFiscal;
        executarAcoes();
    }

    public NotaFiscal(double valorBruto, double impostos, List<AcaoPosNotaFiscal> acoesPosNotaFiscal) {
        this(0, valorBruto, impostos, acoesPosNotaFiscal);
        executarAcoes();
    }

    private void executarAcoes() {
        if (this.acoesPosNotaFiscal != null) {
            for (AcaoPosNotaFiscal acao : this.acoesPosNotaFiscal) {
                acao.acao(this);
            }
        }
    }

    public int getId() {
        return id;
    }

    public double getValorBruto() {
        return valorBruto;
    }

    public double getImpostos() {
        return impostos;
    }

    public double getValorLiquido() {
        return this.valorBruto - this.impostos;
    }
}

Com isto a classe GeradorDeNotaFiscal, não seria mais necessária, pois seria resumido à isto:

public static void main(String[] args) {
        Fatura fatura = new Fatura(2000.00, "Phelipe", new ImpostoSimples());
        fatura.gerarNotaFiscal(null);
}

Ou à isto:

    public static void main(String[] args) {
        Fatura fatura = new Fatura(2000.00, "Phelipe", new ImpostoSimples());

        List<AcaoPosNotaFiscal> acoesPosNotaFiscal = new ArrayList<AcaoPosNotaFiscal>();
        acoesPosNotaFiscal.add(new Hotmail());

        fatura.gerarNotaFiscal(acoesPosNotaFiscal);
    }

O segundo construtor da classe NotaFiscal não precisa chamar o método executarAcoes(), pois ele já esta sendo chamado no construtor referenciado this. Então fica assim:

public NotaFiscal(int id, double valorBruto, double impostos, List<AcaoPosNotaFiscal> acoesPosNotaFiscal) {
        this.id = id;
        this.valorBruto = valorBruto;
        this.impostos = impostos;
        this.acoesPosNotaFiscal = acoesPosNotaFiscal;
        executarAcoes();
    }

    public NotaFiscal(double valorBruto, double impostos, List<AcaoPosNotaFiscal> acoesPosNotaFiscal) {
        this(0, valorBruto, impostos, acoesPosNotaFiscal);
    }

Ajudou a expandir meu horizontes :)

Seu exemplo está ainda melhor que o da aula