Campanha pelo uso moderado de if

Publicado: 5 de janeiro de 2016 em Uncategorized
Tags:

Os dois comandos que eu menos gosto nas linguagens de programação são o if e o switch-case, então eu procuro sempre usá-los com parcimônia (eita palavra bonita!).

Vou mostrar aqui uma opção simples para eles num cenário onde seu uso costuma ser considerado legítimo: factories.

O cenário

É comum o código ter menos if ao usar polimorfismo.

Neste cenário (os exemplos estão em Java), eu faço um parser em uma mensagem string a fim de obter a mensagem tipada em um objeto.

    public Mensagem parseMensagem(String tipoMensagem, String mensagem) {
         
         MensagemParser parser = ParserFactory.create(tipoMensagem);
         return parser.parse(mensagem);
     }

Então eu tenho parsers especializados em interpretar diferentes tipos de mensagens string.

Como eu sou muito esperto, eu fiz com que os parsers implementassem uma interface comum (MensagemParser), de modo que eu posso interpretar todos os tipos de mensagens com um único bloco de código.

Assim, graças ao polimorfimsmo do parser entregue pelo factory, não interessa quantos tipos de mensagem existam, eu trato todos da mesma maneira. Bacana!

Mas mesmo usando polimorfimsmo ainda caímos nos ifs na hora de implementar o factory :-/

Exemplo de factory usando if

O meu factory usando if fica assim:

    class ParserFactory {
        static MensagemParser create(String tipoMensagem) {
             
             if ("A".equals(tipoMensagem)) {
                 return new AParser();
             } else if ("B".equals(tipoMensagem)) {
                 return new BParser();
             } else if ("C".equals(tipoMensagem)) {
                 return new CParser();
             } else {
                 return new DParser();
             }
         }
     }

Usando case ficaria semelhante (semelhantemente ruim hahaha).

Exemplo de factory usando um dicionário em vez de if

Agora, vejamos como ficaria o meu parser usando um dicionário (ou “map”) em vez de if:

    class ParserFactory {
        private static Map<String, MensagemParser> parsers = new HashMap<>();
         static {
             parsers.put("A",      new AParser());
             parsers.put("B",      new BParser());
             parsers.put("C",      new CParser());
             parsers.put("D",      new DParser());
         }
         
         static MensagemParser create(String tipoMensagem) {
              return parsers.get(tipoMensagem);
         }
     }

Na minha opinião, este segundo exemplo é menos imperativo e mais declarativo; o código fica mais simples, mais legível. O que você acha?

Considerações

Este é um exemplo de factory bem básico, mas eu tenho usado o conceito com sucesso em casos mais complexos também.

Por exemplo, se precisar retornar uma nova instância do parser a cada requisição, basta guardar o tipo no dicionário em vez de guardar a própria instância.

Em Java também é possível usar enumerations para obter resultado semelhante, já que em Java um enum pode ter propriedades e métodos.

Além disso, o conceito também é válido para outras coisas além de factories. O dicionário poderia conter outros tipos de objetos (inclusive como índice, no lugar de string) e, em outras linguagens, poderia conter funções/ações/delegates.

É claro que se fosse necessário validar o tipo da mensagem talvez fosse preciso usar um if. Mas daí seria um único if em vez de muitos.

Fim.

 

comentários

Deixe um comentário