Java: colisión de nombres de métodos en la implementación de la interfaz
Si tengo dos interfaces, ambas bastante diferentes en sus propósitos, pero con la misma firma de método, ¿cómo hago para que una clase implemente ambas sin tener que escribir un solo método que sirva para ambas interfaces y escribir alguna lógica complicada en el método? ¿Implementación que verifica qué tipo de objeto se realiza la llamada e invoca el código adecuado?
En C#, esto se soluciona mediante lo que se denomina implementación de interfaz explícita. ¿Existe alguna forma equivalente en Java?
No, no hay forma de implementar el mismo método de dos maneras diferentes en una clase en Java.
Esto puede llevar a muchas situaciones confusas, razón por la cual Java no lo permite.
interface ISomething {
void doSomething();
}
interface ISomething2 {
void doSomething();
}
class Impl implements ISomething, ISomething2 {
void doSomething() {} // There can only be one implementation of this method.
}
Lo que puede hacer es componer una clase a partir de dos clases, cada una de las cuales implementa una interfaz diferente. Entonces esa clase tendrá el comportamiento de ambas interfaces.
class CompositeClass {
ISomething class1;
ISomething2 class2;
void doSomething1(){class1.doSomething();}
void doSomething2(){class2.doSomething();}
}
No existe una forma real de resolver esto en Java. Podrías usar clases internas como solución alternativa:
interface Alfa { void m(); }
interface Beta { void m(); }
class AlfaBeta implements Alfa {
private int value;
public void m() { ++value; } // Alfa.m()
public Beta asBeta() {
return new Beta(){
public void m() { --value; } // Beta.m()
};
}
}
Aunque no permite conversiones desde AlfaBeta
a Beta
, las conversiones abatidas generalmente son malas, y si se puede esperar que una Alfa
instancia a menudo también tenga un Beta
aspecto, y por alguna razón (generalmente la optimización es la única razón válida), desea poder para convertirlo a Beta
, puede crear una subinterfaz Alfa
con Beta asBeta()
en él.
Si se encuentra con este problema, lo más probable es que se deba a que está utilizando la herencia donde debería utilizar la delegación . Si necesita proporcionar dos interfaces diferentes, aunque similares, para el mismo modelo de datos subyacente, entonces debe usar una vista para proporcionar acceso económico a los datos mediante alguna otra interfaz.
Para dar un ejemplo concreto para el último caso, supongamos que desea implementar ambos Collection
y MyCollection
(que no hereda Collection
y tiene una interfaz incompatible). Podría proporcionar funciones a Collection getCollectionView()
y MyCollection getMyCollectionView()
que proporcionen una implementación ligera de Collection
y MyCollection
, utilizando los mismos datos subyacentes.
Para el primer caso... supongamos que realmente desea una serie de números enteros y una serie de cadenas. En lugar de heredar de ambos List<Integer>
y List<String>
, debe tener un miembro de tipo List<Integer>
y otro miembro de tipo List<String>
y hacer referencia a esos miembros, en lugar de intentar heredar de ambos. Incluso si solo necesita una lista de números enteros, en este caso es mejor usar composición/delegación en lugar de herencia.