java - resueltos - metodo abstracto ejemplo
¿Puedo tener una clase de generador abstracto en java con encadenamiento de métodos sin realizar operaciones no seguras? (3)
Estoy tratando de tener una clase base abstracta para algunas clases de constructor para poder reutilizar fácilmente el código entre las implementaciones de Generador. Quiero que mis constructores admitan el encadenamiento de métodos, por lo tanto, un método debe devolver "esta" instancia del tipo más específico. Pensé que probablemente podría hacer esto con los genéricos. Desafortunadamente no logré hacerlo sin utilizar operaciones inseguras. ¿Es posible?
Código de muestra de cómo lo estoy probando (y cómo funciona) a continuación. Me gustaría evitar enviar a T en "foo ()" (lo que provoca una advertencia sin marcar), ¿se puede hacer esto?
public class Builders
{
public static void main( final String[] args )
{
new TheBuilder().foo().bar().build();
}
}
abstract class AbstractBuilder<T extends AbstractBuilder<?>>
{
public T foo()
{
// set some property
return (T) this;
}
}
class TheBuilder extends AbstractBuilder<TheBuilder>
{
public TheBuilder bar()
{
// set some other property
return this;
}
public Object build()
{
return new Object();
}
}
Desea declarar T
como se extends AbstractBuilder<T>
en AbstractBuilder
.
Utilice un método abstract protected
para obtener this
de tipo T
abstract class AbstractBuilder<T extends AbstractBuilder<T>> {
protected abstract T getThis();
public T foo() {
// set some property
return getThis();
}
}
class TheBuilder extends AbstractBuilder<TheBuilder> {
@Override protected TheBuilder getThis() {
return this;
}
...
}
Alternativamente, descarte el parámetro de tipo genérico, confíe en los tipos de retorno covariante y haga que el código sea más limpio para los clientes (aunque normalmente usarían TheBuilder
lugar de los detalles de implementación en gran medida de la clase base), si se trata de una implementación más detallada.
Esto debería ayudar:
abstract class AbstractBuilder<T extends AbstractBuilder<?>>
{
public AbstractBuilder<T> foo()
{
// set some property
return (AbstractBuilder<T>) this;
}
abstract AbstractBuilder<T> bar();
abstract Object build();
}
Una alternativa es no usar genéricos, pero usar reemplazos:
abstract class AbstractBuilder
{
public AbstractBuilder foo()
{
// set some property
return this;
}
}
class TheBuilder extends AbstractBuilder
{
@Override public TheBuilder foo()
{
super.foo(); return this;
}
public TheBuilder bar()
{
// set some other property
return this;
}
public Object build()
{
return new Object();
}
}