Una clase abstracta de Java con un oyente que utiliza la clase concreta en su devolución de llamada

Heath fronteras:

Quiero tener una clase Java resumen así:

abstract class AbstractFoo<F extends AbstractFoo<F, L>, L extends FooListener<F, L>> {
  private final Class<L> listenerClass;
  protected AbstractFoo(Class<L> listenerClass) {
    this.listenerClass = listenerClass;
  }

  interface FooListener<F extends AbstractFoo<F, L>, L extends FooListener<F, L>> {
    void callback(F foo);
  }

  // Bar might implement FooListener, but I don't control it,
  // so I have no guarantee
  public void externalMethod(Bar bar) {
    if (listenerClass.isInstance(bar)) {
      L listener = listenerClass.cast(bar);

      listener.callback(this); // does not compile
    }
  }
}

listener.callback(this);no se compila porque no hay garantía de que thises del mismo tipo que F. ¿Es posible garantizar de alguna manera que Fes un subtipo de él this?

sfiss:

Lo que estamos tratando de hacer es emular el tipo AUTO en Java utilizando genéricos. Vea este enlace o un sitio diferente para algunos medios para hacerlo. Sin embargo, no hay manera de hacer cumplir que F (o del tipo de auto) es en realidad el mismo tipo, por ejemplo (véase el parámetro tipo de ConcreteFoo2):

static class Bar implements FooListener<ConcreteFoo, Bar> {

    @Override
    public void callback(final ConcreteFoo foo) {
        // TODO Auto-generated method stub

    }

}

static class ConcreteFoo2 extends AbstractFoo<ConcreteFoo, Bar> {

    protected ConcreteFoo2(final Class<Bar> listenerClass) {
        super(listenerClass);
    }

}

static class ConcreteFoo extends AbstractFoo<ConcreteFoo, Bar> {

    protected ConcreteFoo(final Class<Bar> listenerClass) {
        super(listenerClass);
    }

}

En lugar de ir más allá de esta manera, me gustaría primero pensar en las opciones de diseño que haya que condujo hasta aquí:

  • ¿Los oyentes realmente necesitan saber la clase concreta?

  • ¿El AbstractFoo realmente necesita saber la aplicación concreta de la clase oyente?

Tal vez un menor número de parámetros de tipo son en realidad la solución, apoyándose en las interfaces solo.


EDIT: Una posible solución, si no quiere fundido (F) thissería proporcionar un método abstracto protected abstract F getSelf();que las implementaciones concretas implementan mediante la devolución this.

Ver el código simplificado por ejemplo:

static final class Bar implements FooListener<ConcreteFoo> {

    @Override
    public void callback(final ConcreteFoo foo) {
        // TODO Auto-generated method stub

    }

}

static final class ConcreteFoo extends AbstractFoo<ConcreteFoo> {

    protected ConcreteFoo(final Class<? extends FooListener<ConcreteFoo>> listenerClass) {
        super(listenerClass);
    }

    @Override
    protected ConcreteFoo getSelf() {
        return this;
    }

}

static abstract interface FooListener<FOO extends AbstractFoo<FOO>> {

    void callback(FOO abstractFoo);
}

static abstract class AbstractFoo<SELF extends AbstractFoo<SELF>> {

    private final Class<? extends FooListener<SELF>> listenerClass;

    protected AbstractFoo(final Class<? extends FooListener<SELF>> listenerClass) {
        this.listenerClass = listenerClass;
    }

    protected abstract SELF getSelf();

    // Bar might implement FooListener, but I don't control it,
    // so I have no guarantee
    public void externalMethod(final Bar bar) {
        if (listenerClass.isInstance(bar)) {
            final FooListener<SELF> listener = listenerClass.cast(bar);

            listener.callback(getSelf()); // compiles
        }
    }
}

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=213896&siteId=1
Recomendado
Clasificación