Evitando null-checks com NullObject Pattern

Eduardo Souza
Contabilizei
Published in
2 min readMay 4, 2021

--

Photo by Irvan Smith on Unsplash

Com certeza você já se deparou com algum código parecido com o abaixo. Temos objetos, que geralmente implementam uma superclasse e, em algum momento, antes de chamar algum método, precisamos saber (e tratar) o caso de alguma dessas referências for nula.

Ao executar o código, nos deparamos com a seguinte exception:

Exception in thread "main" java.lang.NullPointerException
at Scratch.main(scratch_9.java:41)

O Tratamento de nulos é um grande problema em linguagens de programação. Um atributo nulo não tratado pode levar às famosas NullPointerExceptions, que tanto atormentam a vida de muitos desenvolvedores.

Para evitar que a exceção seja lançada, precisaríamos tratar a exceção e o código do método main ficaria mais ou menos assim:

Bem ruim de ler não é?

Acontece que existe um Padrão de Projeto pouco conhecido e utilizado por programadores. Este padrão é o NullObject.

O padrão NullObject

O NullObject é um padrão de projeto que simplifica o uso de objetos dependentes que, em algum momento, podem ser indefinidos. Assim, ao invés de usar referências com null, utilizamos o NullObject como instância de um interface bem conhecida.

Para evitarmos fazer checagem e tratamento de referências nulas, definimos uma classe abstrata com todas as operações que necessitamos, criando classes concretas que implementam esses comportamentos. Também criamos uma instância do NullObject que simplesmente não faz nada, que utilizaremos para evitar a checagem de objetos nulos.

Assim, a hierarquia de classes, com base no código acima, ficaria da seguinte maneira, com o NullObject declarado.

Mas ok, onde está a diferença no tratamento de nulos? A diferença vai estar no momento em que você precisar das referências nulas. Ao invés de atribuir null , irá utilizar um a referência do NullObject. Assim, ao reescrevermos o código acima com o uso do NullObject, ficaria mais ou menos da seguinte maneira:

E a saída ficaria assim:

Processando algo para tipoConcreto 1
Processando algo para tipoConcreto 2

Bem mais simples não é mesmo?

PS: Para não ficar no escuro, seria interessante lançar um log na Factory para indicar quando um valor não for encontrado.

--

--

Desenvolvedor Backend Kotlin/Java e Tech Leader na Contabilizei e também palpiteiro nas horas vagas..