Handler Map

André MartinsAndré Martins
2 min read

Imagine que você está em um cenário onde tem várias funções que precisam ser executadas conforme um caminho seja passado por parâmetro, por exemplo: dentro de um domínio de clientes, precisamos executar funções a partir de uma chamada desse path, e, nesse caso, temos sabedoria para não resolver isso com switch case ou da forma abaixo.

class Cliente {
  public constructor(private _id: number, private _name: string) {}

  get clientes(): number {
    return this._id;
  }

  // outros comportamentos do cliente
}

class ClienteService {
  public execute(path: string) {
    if (path === "sincronizarImagens") {
      // lógica para sincronizar as imagens do cliente
    }

    if (path === "sincronizarReport") {
      // lógica para sincronizar os relatórios do cliente
    }

    if (path === "sincronizarLogs") {
      // lógica para sincronizar os logs do cliente
    }
  }
}

Iniciando solução

Podemos pensar em excluir essa lógica de ifs, e uma forma de fazer isso é com o Handler Map.

A primeira parte é definir um tipo onde teremos uma chave e o tipo de parâmetros da função de callback. Perceba que, nesse ponto, podemos usar qualquer string como tipo da chave, e nos parâmetros estamos esperando o ID e não vamos retornar nada.

type HandlerMap = {
  [key: string]: (id: number) => void;
};

Agora precisamos de uma função para resolver nossa callback conforme o parâmetro que passarmos, mas o detalhe é que não vamos passar parâmetro nenhum, te mostro já.

class ClientService {
    private resolverHandlerMapByName(): HandlerMap {
        return {
            sincronizarImagens:(id: number) => this.searchImages(id),
            sincronizarReport(id: number) => this.sincronizarReport(id),
            sincronizarLogs(id: number) => this.sincronizarLogs(id),
        }
    }

    sincronizarImagens(id: number): void {
        // lógica para sincronizar as imagens do cliente
    }

    sincronizarReport(id: number): void {
        // lógica para sincronizar os relatórios do cliente
    }

    sincronizarLogs(id: number): void {
        // lógica para sincronizar os logs do cliente
    }
}

Conforme o exemplo acima, resolvemos nossa execução de forma transparente, sem a necessidade de verificações estranhas.

Como usar?

class ClientService {

    execute(path: string) {

        const id = 123;

        const handler = this.resolverHandlerMapByName()[path]

        handler(id);

    }

    private resolverHandlerMapByName(): HandlerMap {
        return {
            sincronizarImagens:(id: number) => this.searchImages(id),
            sincronizarReport(id: number) => this.sincronizarReport(id),
            sincronizarLogs(id: number) => this.sincronizarLogs(id),
        }
    }

    sincronizarImagens(id: number): void {
        // lógica para sincronizar as imagens do cliente
    }

    sincronizarReport(id: number): void {
        // lógica para sincronizar os relatórios do cliente
    }

    sincronizarLogs(id: number): void {
        // lógica para sincronizar os logs do cliente
    }
}

Dessa forma conseguimos resolver nossa chamada com HandlerMap de forma transparente, há outras formas de resolver isso também, mas essa é uma forma que deixa as coisas bem legíveis.

0
Subscribe to my newsletter

Read articles from André Martins directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

André Martins
André Martins