Callbacks en Java

Hace días necesitaba implementar algo en Java que me permitiera emular callbacks. Habiendo usado tanto tiempo Java fue curioso que de primera instancia no se me ocurriera usar interfaces. Un googlazo me enseñó la luz, y de ahí en delante fue nada más crear las clases necesarias.

El escenario es el siguiente: hay una clase que hace las veces de fábrica para crear instancias de otra, pero la forma de extraer la información es diferente dependiendo del documento en cuestión. Cada documento está clasificado en grupos, por lo que sé qué reglas tengo que usar para extraer lo de cada grupo. Ciertamente podría hacer todo con un parámetro y revisar el valor con un if para saber qué rutina ejecutar, pero si existen los callbacks, qué mejor (aunque Java no usa apuntadores).

Lo primero es crear la interface que las clases se van a cargar de implementar. Algo como:

public interface OmniAnalyzer {
    public void analyzeDocument(String document);
}

Después, hay que crear una clase por cada grupo de documentos a analizar, y hacer que cada una implemente la interface arriba mostrada:

public class GroupAAnalyzer implements OmniAnalyzer {
    @Override
    public void analyzeDocument(String document) {
       // Analizar documento de acuerdo a reglas de grupo A
    }
}
public class GroupBAnalyzer implements OmniAnalyzer {
   @Override
   public void analyzeDocument(String document) {
       // Analizar documento de acuerdo a reglas de grupo B
   }
}

Y al momento de analizar un documento, en vez de declarar que usamos una instancia de alguna de las clases anteriores, referenciamos directamente la interface que implementan. Así, independientemente de la clase (y las reglas) que se utilice, simplemente hay que llamar a las funciones que sabemos que están implementadas.

public class General {

  private static void analyzeDocument(OmniAnalyzer analyzer, String document) {
    analyzer.analyzeDocument(document);
  }

  public static void main(String a[]) {
    String doc = a[0];
    int group = Integer.parseInt(a[1]);
    OmniAnalyzer analyzer = null;

    if (group == 0)
     analyzer = new GroupAAnalyzer();
    else if (group == 1)
     analyzer = new GroupBAnalyzer();
    else {
       System.err.println("Only accepting groups 0 or 1");
       System.exit(1);
    }

    analyzeDocument(analyzer, doc);
  }
}

Con esto se deja la puerta abierta para agregar nuevos grupos en caso de ser necesario, y sin necesidad de darle en la torre a lo que ya está hecho.