[java] Constructor en una interfaz?



Answers

Un problema que obtienes al permitir constructores en las interfaces proviene de la posibilidad de implementar varias interfaces al mismo tiempo. Cuando una clase implementa varias interfaces que definen diferentes constructores, la clase tendría que implementar varios constructores, cada uno satisfaciendo solo una interfaz, pero no las otras. Será imposible construir un objeto que llame a cada uno de estos constructores.

O en el código:

interface Named { Named(String name); }
interface HasList { HasList(List list); }

class A implements Named, HasList {

  /** implements Named constructor.
   * This constructor should not be used from outside, 
   * because List parameter is missing
   */
  public A(String name)  { 
    ...
  }

  /** implements HasList constructor.
   * This constructor should not be used from outside, 
   * because String parameter is missing
   */
  public A(List list) {
    ...
  }

  /** This is the constructor that we would actually 
   * need to satisfy both interfaces at the same time
   */ 
  public A(String name, List list) {
    this(name);
    // the next line is illegal; you can only call one other super constructor
    this(list); 
  }
}
Question

Sé que no es posible definir un constructor en una interfaz. Pero me pregunto por qué, porque creo que podría ser muy útil.

Por lo tanto, puede estar seguro de que se definen algunos campos en una clase para cada implementación de esta interfaz.

Por ejemplo, considere la siguiente clase de mensaje:

public class MyMessage {

   public MyMessage(String receiver) {
      this.receiver = receiver;
   }

   private String receiver;

   public void send() {
      //some implementation for sending the mssage to the receiver
   }
}

Si defino una interfaz para esta clase para poder tener más clases que implementen la interfaz del mensaje, solo puedo definir el método de envío y no el constructor. Entonces, ¿cómo puedo asegurarme de que cada implementación de esta clase realmente tenga un receptor configurado? Si utilizo un método como setReceiver(String receiver) no puedo estar seguro de que se llame realmente este método. En el constructor podría asegurarlo.




Solo hay campos estáticos en la interfaz que no necesitan inicializarse durante la creación del objeto en la subclase y el método de la interfaz debe proporcionar la implementación real en la subclase. Por lo tanto, no es necesario el constructor en la interfaz.

Segundo motivo: durante la creación del objeto de la subclase, se llama al constructor padre. Pero si hay más de una interfaz implementada, se producirá un conflicto durante la llamada del constructor de la interfaz en cuanto al constructor de la interfaz que llamará primero




Un trabajo que puede intentar es definir un método getInstance() en su interfaz para que el implementador sepa qué parámetros deben manejarse. No es tan sólido como una clase abstracta, pero permite una mayor flexibilidad como interfaz.

Sin embargo, esta solución requiere que use getInstance() para crear una instancia de todos los objetos de esta interfaz.

P.ej

public interface Module {
    Module getInstance(Receiver receiver);
}



Vea esta pregunta por el por qué (tomado de los comentarios).

Si realmente necesita hacer algo como esto, es posible que desee una clase base abstracta en lugar de una interfaz.




Aquí hay un ejemplo usando esta Técnica. En este ejemplo específico, el código realiza una llamada a Firebase utilizando un MyCompletionListener falso que es una interfaz enmascarada como clase abstracta, una interfaz con un constructor

private interface Listener {
    void onComplete(databaseError, databaseReference);
}

public abstract class MyCompletionListener implements Listener{
    String id;
    String name;
    public MyCompletionListener(String id, String name) {
        this.id = id;
        this.name = name;
    }
}

private void removeUserPresenceOnCurrentItem() {
    mFirebase.removeValue(child("some_key"), new MyCompletionListener(UUID.randomUUID().toString(), "removeUserPresenceOnCurrentItem") {
        @Override
        public void onComplete(DatabaseError databaseError, DatabaseReference databaseReference) {

        }
    });
    }
}

@Override
public void removeValue(DatabaseReference ref, final MyCompletionListener var1) {
    CompletionListener cListener = new CompletionListener() {
                @Override
                public void onComplete(DatabaseError databaseError, DatabaseReference databaseReference) {
                    if (var1 != null){
                        System.out.println("Im back and my id is: " var1.is + " and my name is: " var1.name);
                        var1.onComplete(databaseError, databaseReference);
                    }
                }
            };
    ref.removeValue(cListener);
}



Related