Como hacer dos clases que ambos tienen método con el mismo nombre, la firma y el tipo de retorno se comportan como si fuera a poner en práctica la misma interfaz

Lucas:

Voy a explicar mi pregunta sobre el ejemplo.

Tengo dos clases NumberGeneratorAppley NumberGeneratorOrange. Ambos tienen método con la misma firma y la devolución tipo public Integer getNumber(). El problema es que no implementan la misma interfaz aunque incluya sería lógico. Podría hacer interfaz con este método y modificar estas clases de ponerlo en práctica, pero no quiero hacerlo. He aquí por qué. Estas clases se generan automáticamente a partir de XML digamos de let. En el ejemplo real hay de tales clases docenas. Tenemos que generarlos de vez en cuando y se sobrescribe los antiguos. No quiero cambiar manualmente cada clase para implementar la interfaz después de cada generación. También puede que no sea obvio que se debe hacer por alguna otra persona de trabajo en el mismo proyecto, e incluso para mí después de algún tiempo.
Aquí está la primera clase:

public class NumberGeneratorApple {
    public Integer getNumber(){
        return 9;
    }
}  

y la segunda:

public class NumberGeneratorOrange {
    public Integer getNumber(){
        return 19;
    }
}

Althought que no implementan la misma interfaz que necesito utilizar de una manera genérica. Sólo quiero hacer algo como esto:

public class ClassThatOperates<T extends NumberGeneratorInterface> {
    T generator;

    public ClassThatOperates(T generator) {
        this.generator = generator;
    }

    public void doSomeOperation(){
        //Obviously it won't work for NumberGeneratorApple and NumberGeneratorOrange
        // because they do not implement NumberGeneratorInterface
        //And if I change "<T extends NumberGeneratorInterface>" to "<T>"
        // I cannot write method call "generator.getNumber()"
        System.out.print("The number with constant is: ");
        System.out.println(generator.getNumber() + 5);
    }
}

Esta es la interfaz (sé pública no es necesaria allí y es allí de forma predeterminada sólo quiero hacer hincapié en ella.):

public interface NumberGeneratorInterface {
    public Integer getNumber();
}

Como se puede ver que es imposible hacer tal cosa porque ni NumberGeneratorAppleni NumberGeneratorOrangeimplementos NumberGeneratorInterface. Sin embargo, me encontré con un poco de solución, pero siguiendo mi instinto creo que es más bien pobre. Hice clases de contenedor:

public class NumberGeneratorAppleWrapper extends NumberGeneratorApple implements NumberGeneratorInterface {
}

y

public class NumberGeneratorOrangeWrapper extends NumberGeneratorOrange implements NumberGeneratorInterface {
}

Es un poco complicado. Puede ser que sea no es evidente al principio, pero cuando se llama obtieneNumero () en el objeto de una de estas clases que llamas, de hecho, algo como esto:

@Override
public Integer getNumber() {
    return super.getNumber();
}

Ahora puedo llamar de esta manera:

public class Main {
    public static void main(String[] args) {
        ClassThatOperates<NumberGeneratorAppleWrapper> classThatOperatesApple = new ClassThatOperates<>(new NumberGeneratorAppleWrapper());
        ClassThatOperates<NumberGeneratorOrangeWrapper> classThatOperatesOrange = new ClassThatOperates<>(new NumberGeneratorOrangeWrapper());
        classThatOperatesApple.doSomeOperation();
        classThatOperatesOrange.doSomeOperation();
    }
}

Y me da el siguiente resultado:

The number with constant is: 14
The number with constant is: 24

La ventaja de este enfoque en lugar de añadir manualmente implements NumberGeneratorInterfacea cada clase generada es que nosotros no tenemos que repetir el mismo trabajo después de cada generación (que anula las clases de edad). Sólo tenemos que añadir un nuevo envoltorio cuando los resultados de generación en algunos nuevos, clase adicional.

Sé que en tal escenario que puede deshacerse de los genéricos en ClassThatOperatesy justo declaro NumberGeneratorInterface generator;sin <T extends...>y así sucesivamente (e incluso debería) por lo que el código podría ser más simple, pero quiero que este ejemplo sea bastante similar a lo que he encontrado en algún proyecto de bienes . Me escribió: Tengo, hice, se me ocurrió, etc, pero en realidad está basado en el código ya existente que he encontrado en algún proyecto.

No son mis preguntas:
1. ¿Hay una solución mejor?
2. ¿Es esta solución el llamado "mal gusto"?
3. Si tengo que utilizar dicha solución tal vez todo mi enfoque es erróneo?
4. Si no hay una solución mejor, incluso si todo el enfoque es erróneo lo que podría mejorarse en este código (incluyendo Deshacerse de los genéricos)?

rgettman:
  1. ¿Hay una solución mejor?

Su solución se ve bien para mí. Ha utilizado la adapter , que utiliza funcionalidades existentes para ajustarse a una interfaz de otro modo no relacionado. Sin cambiar NumberGeneratorAppley NumberGeneratorOrange, que ha adaptado la funcionalidad de esas clases a NumberGeneratorInterface.

De manera más general, puede haber métodos existentes con diferentes firmas que adaptarse a una interfaz, por ejemplo, si usted tenía

public class NumberGeneratorApple {
    public Integer getAppleNumber(){
        return 9;
    }
}

Entonces su clase de adaptador podría llamar explícitamente a getAppleNumberla hora de implementar la interfaz.

public class NumberGeneratorAppleWrapper extends NumberGeneratorApple implements NumberGeneratorInterface {
    @Override
    public Integer getNumber() {
        return getAppleNumber();
    }
}
  1. Esta solución es el llamado "mal gusto"?

Esta solución no deja mal sabor de boca. El adapter es un patrón de diseño de software bien establecida.

  1. Si tengo que utilizar dicha solución tal vez todo mi enfoque es erróneo?

Si no puede cambiar de clase existentes, tales como NumberGeneratorApple, entonces el adapter es el camino a seguir. Si usted puede cambiarlos, a continuación, sólo tiene las clases implementan la interfaz necesaria directamente.

public class NumberGeneratorApple implements NumberGeneratorInterface {
    @Override
    public Integer getNumber() {
        return 9;
    }
}

O, si la firma del método es diferente:

public class NumberGeneratorApple implements NumberGeneratorInterface {
    public Integer getAppleNumber() {
        return 9;
    }

    @Override
    public Integer getNumber() {
        return getAppleNumber();
    }
}
  1. Si no hay una solución mejor, incluso si todo el enfoque es erróneo lo que podría mejorarse en este código (incluyendo Deshacerse de los genéricos)?

Si sus clases como NumberGeneratorApplerealmente tienen exactamente un método, y no son sólo simplificaciones de las clases más complejas con múltiples métodos para los fines de esta pregunta, entonces usted puede utilizar referencias de métodos como otra respuesta ha insinuado. En lugar de declarar su propia interfaz NumberGeneratorInterface, una referencia método puede ser escrito como una Supplier<Integer>.

public class ClassThatOperates {
    Supplier<Integer> generator;

    public ClassThatOperates(Supplier<Integer> generator) {
        this.generator = generator;
    }

    public void doSomeOperation(){
        System.out.print("The number with constant is: ");
        System.out.println(generator.get() + 5);
    }
}

A continuación, puede utilizarlo como:

NumberGeneratorOrange ngo = new NumberGeneratorOrange();
ClassThatOperates cto = new ClassThatOperates(ngo::getNumber);
cto.doSomeOperation();

Supongo que te gusta

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