Java-Colisión del nombre del método en la implementación de la interfaz


Si tengo dos interfaces , ambas muy diferentes en sus propósitos , pero con la misma firma de método, ¿cómo puedo hacer que una clase implemente ambas sin tener que escribir un único método que sirva para ambas interfaces y escribir alguna lógica enrevesada en la implementación del método que verifique para qué tipo de objeto se está haciendo la llamada e invoque el código adecuado ?

En C# , esto es superado por lo que se llama implementación de interfaz explícita. ¿Hay algún equivalente ¿en Java ?

Author: YCF_L, 2010-04-08

7 answers

No, no hay manera de implementar el mismo método de dos maneras diferentes en una clase en Java.

Eso puede llevar a muchas situaciones confusas, por lo que Java no lo ha permitido.

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 de dos clases que cada una implemente 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();}
}
 71
Author: jjnguy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-04-08 06:44:56

No hay una manera real de resolver esto en Java. Puedes 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 casts de AlfaBeta a Beta, los downcasts son generalmente malos, y si se puede esperar que una instancia Alfa a menudo también tenga un aspecto Beta, y por alguna razón (generalmente la optimización es la única razón válida) desea poder convertirla a Beta, podría hacer una sub-interfaz de Alfa con Beta asBeta() en ella.

 13
Author: gustafc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-04-08 14:03:04

Si se encuentra con este problema, lo más probable es que esté usando herencia donde debería usar delegación. Si necesita proporcionar dos interfaces diferentes, aunque similares, para el mismo modelo subyacente de datos, entonces debe usar una vista para proporcionar acceso a los datos a bajo costo utilizando alguna otra interfaz.

Para dar un ejemplo concreto en este último caso, supongamos que desea implementar Collection y MyCollection (que no heredar de Collection y tiene una interfaz incompatible). Podría proporcionar funciones Collection getCollectionView() y MyCollection getMyCollectionView() que proporcionan una implementación ligera de Collection y MyCollection, utilizando los mismos datos subyacentes.

Para el primer caso... supongamos que realmente desea una matriz de enteros y una matriz de cadenas. En lugar de heredar de List<Integer> y List<String>, debe tener un miembro de tipo List<Integer> y otro miembro de tipo List<String>, y referirse a esos miembros, en lugar de tratar de heredar de ambos. Incluso si solo necesita una lista de enteros, es mejor usar composición / delegación sobre herencia en este caso.

 11
Author: Michael Aaron Safyan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-25 00:20:30

El problema de Java "clásico" también afecta a mi desarrollo de Android...
La razón parece ser simple:
Más frameworks / bibliotecas que tienes que usar, más fácilmente las cosas pueden estar fuera de control...

En mi caso, tengo un BootStrapperApp clase heredada de android.app.Solicitud,
considerando que la misma clase también debe implementar un Plataforma interfaz de un framework MVVM para integrarse.
Método de colisión ocurrió en un getString() método, el cual es anunciado por ambas interfaces y debe tener bastantes aplicación en diferentes contextos.
La solución (feo..IMO) está utilizando una clase interna para implementar todos los métodos Platform, solo por una firma de método menor conflict...in en algunos casos, tal método prestado ni siquiera se utiliza en absoluto (pero afecta a la semántica de diseño principal).
Tiendo a estar de acuerdo en que la indicación explícita de contexto/espacio de nombres al estilo C#es útil.

 1
Author: tiancheng,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-29 10:01:10

La única solución que vino a mi mente es el uso de objetos de referencia a la que desea implementar interfaces múltiples.

Por ejemplo: supongamos que tiene 2 interfaces para implementar

public interface Framework1Interface {

    void method(Object o);
}

Y

public interface Framework2Interface {
    void method(Object o);
}

Puede encerrarlos en dos objetos Facador:

public class Facador1 implements Framework1Interface {

    private final ObjectToUse reference;

    public static Framework1Interface Create(ObjectToUse ref) {
        return new Facador1(ref);
    }

    private Facador1(ObjectToUse refObject) {
        this.reference = refObject;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof Framework1Interface) {
            return this == obj;
        } else if (obj instanceof ObjectToUse) {
            return reference == obj;
        }
        return super.equals(obj);
    }

    @Override
    public void method(Object o) {
        reference.methodForFrameWork1(o);
    }
}

Y

public class Facador2 implements Framework2Interface {

    private final ObjectToUse reference;

    public static Framework2Interface Create(ObjectToUse ref) {
        return new Facador2(ref);
    }

    private Facador2(ObjectToUse refObject) {
        this.reference = refObject;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof Framework2Interface) {
            return this == obj;
        } else if (obj instanceof ObjectToUse) {
            return reference == obj;
        }
        return super.equals(obj);
    }

    @Override
    public void method(Object o) {
        reference.methodForFrameWork2(o);
    }
}

Al final la clase que querías debería algo como

public class ObjectToUse {

    private Framework1Interface facFramework1Interface;
    private Framework2Interface facFramework2Interface;

    public ObjectToUse() {
    }

    public Framework1Interface getAsFramework1Interface() {
        if (facFramework1Interface == null) {
            facFramework1Interface = Facador1.Create(this);
        }
        return facFramework1Interface;
    }

    public Framework2Interface getAsFramework2Interface() {
        if (facFramework2Interface == null) {
            facFramework2Interface = Facador2.Create(this);
        }
        return facFramework2Interface;
    }

    public void methodForFrameWork1(Object o) {
    }

    public void methodForFrameWork2(Object o) {
    }
}

Ahora puede usar los métodos getAs * para" exponer " su clase

 1
Author: notAtAll,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-21 17:41:15

Puede utilizar un patrón de adaptador para que estos funcionen. Cree dos adaptadores para cada interfaz y utilícelos. Debería resolver el problema.

 0
Author: AlexCon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-01 21:39:44

Todo bien cuando usted tiene control total sobre todo el código en cuestión y puede implementar esto por adelantado. Ahora imagine que tiene una clase pública existente utilizada en muchos lugares con un método

public class MyClass{

    private String name;

    MyClass(String name){
        this.name = name;
    }

    public String getName(){
        return name;
    }
}

Ahora necesita pasarlo al WizzBangProcessor que requiere clases para implementar el WBPInterface... que también tiene un método getName (), pero en lugar de su implementación concreta, esta interfaz espera que el método devuelva el nombre de un tipo de Wizz Bang Procesamiento.

En C # sería un trvial

public class MyClass : WBPInterface{

    private String name;

    String WBPInterface.getName(){
        return "MyWizzBangProcessor";
    }

    MyClass(String name){
        this.name = name;
    }

    public String getName(){
        return name;
    }
}

En Java Tough vas a tener que identificar cada punto en la base de código desplegado existente donde necesitas convertir de una interfaz a la otra. Claro que la compañía WizzBangProcessor debería haber usado getWizzBangProcessName (), pero también son desarrolladores. En su contexto getName estaba bien. En realidad, fuera de Java, la mayoría de los otros lenguajes basados en OO soportan esto. Java es raro en forzar todas las interfaces para ser implementadas con el mismo nombre del método.

La mayoría de los otros lenguajes tienen un compilador que está más que feliz de tomar una instrucción para decir "este método en esta clase que coincide con la firma de este método en esta interfaz implementada es su implementación". Después de todo, el objetivo de definir interfaces es permitir que la definición se abstraiga de la implementación. (Ni siquiera me haga empezar a tener métodos predeterminados en Interfaces en Java, y mucho menos por defecto sobreescritura.... porque seguro, cada componente diseñado para un coche de carretera debe ser capaz de conseguir golpeado contra un coche volador y solo el trabajo - hey, ambos son coches... Estoy seguro de que la funcionalidad predeterminada de say your sat nav no se verá afectada con las entradas predeterminadas de pitch y roll, porque los coches solo guiñan!

 -1
Author: user8232920,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-29 16:09:56