Open/closed principle

O princípio de aberto/fechado, letra O do acrônimo de SOLID (Open/close principle) tem como objetivo assegurar que uma entidade de software(classe, método, etc.) seja aberta para extensões porém fechada para modificações (Meyer, Bertrand), ou seja, nossas entidades de softwares devem possibilitar evoluções, mas as alterações não devem alterar comportamentos já existentes.

Uma comum violação desse princípio é quando utilizamos if/else encadeados para comparar valores de enum, como no exemplo a seguir:

public class Fatura {

    private TipoFatura tipoFatura;
    private Integer quantidade;
    private Integer duracao;
    private Integer bytes;
    private BigDecimal valorUnitario;

    public BigDecimal getValorTotal() {
        if(tipoFatura == TipoFatura.VOZ) {
            return valorUnitario.multiply(BigDecimal.valueOf(duracao));
        } else if(tipoFatura == TipoFatura.DADOS) {
            return valorUnitario.multiply(BigDecimal.valueOf(bytes));
        } else {
            return valorUnitario.multiply(BigDecimal.valueOf(quantidade));
        }
    }
}

Qual o problema desse código? É que esse trecho é aberto para extensão, mas também é aberto para modificações, porque se surgir um novo item da na enum e o método getValorTotal() não for atualizado haverá uma modificação no resultado final e também caso surgir novas condições (if/else) o comportamento também pode ser alterado de acordo com as ordens de verificações.

E como resolver esse caso? Simplesmente aplicando polimorfismo conseguimos evitar o problema nesse trecho, onde a própria enum sabe executar o calculo de valor total para cada item, assim além de deixar o código mais legível também deixa o código protegido, respeitando o princípio de aberta/fechado.

public enum TipoFatura {

    VOZ {
        @Override
        public BigDecimal calcularValorTotal(Fatura fatura) {
          return multiply(fatura.getValorUnitario(), fatura.getDuracao());
        }
    },
    DADOS {
        @Override
        public BigDecimal calcularValorTotal(Fatura fatura) {
          return multiply(fatura.getValorUnitario(), fatura.getBytes());
        }
    }

    public abstract BigDecimal calcularValorTotal(Fatura fatura);

}

public BigDecimal getValorTotal() {
    return tipoFatura.calcularValorTotal(this);
}

Com isso, o princípio de aberto/fechado é uma importante prática para sempre estarmos SEMPRE aplicando em nossos códigos, o qual pode parecer um pouco impactante de implementar, até mesmo por isso que esse princípio é mais relacionado ao design da solução, porém é de suma importância, pois códigos abertos a modificações são mais propícios a gerar bugs e bugs que nem sempre são claros ou lançam exception, onde na maioria das vezes são bugs que mudam um resultado final do método o que dificulta sua resolução.

Anúncios

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

Conectando a %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.