web-dev-qa-db-fra.com

Constructeur dans une interface?

Je sais qu'il n'est pas possible de définir un constructeur dans une interface. Mais je me demande pourquoi, parce que je pense que cela pourrait être très utile.

Vous pouvez donc être sûr que certains champs d'une classe sont définis pour chaque implémentation de cette interface.

Par exemple, considérons la classe de message suivante:

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 un définit une interface pour cette classe afin que je puisse avoir plus de classes qui implémentent l'interface de message, je ne peux définir que la méthode send et non le constructeur. Alors, comment puis-je m'assurer que chaque implémentation de cette classe a vraiment un jeu de récepteurs? Si j'utilise une méthode comme setReceiver(String receiver), je ne peux pas être sûr que cette méthode est vraiment appelée. Dans le constructeur, je pouvais m'en assurer.

134
anon

En prenant certaines des choses que vous avez décrites:

"Vous pouvez donc être sûr que certains champs d'une classe sont définis pour chaque implémentation de cette interface."

"Si vous définissez une interface pour cette classe afin d'avoir plus de classes qui implémentent l'interface de message, je ne peux définir que la méthode send et non le constructeur"

... ces exigences sont exactement ce que classes abstraites sont pour.

122
matt b

Un problème que vous rencontrez lorsque vous autorisez les constructeurs dans les interfaces provient de la possibilité d'implémenter plusieurs interfaces en même temps. Lorsqu'une classe implémente plusieurs interfaces définissant différents constructeurs, elle devra implémenter plusieurs constructeurs, chacun ne satisfaisant qu'une interface, mais pas les autres. Il sera impossible de construire un objet qui appelle chacun de ces constructeurs.

Ou en code:

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); 
  }
}
69
daniel kullmann

Une interface définit un contrat pour une API, c'est-à-dire un ensemble de méthodes sur lesquelles l'implémenteur et l'utilisateur de l'API conviennent. Une interface n'a pas d'implémentation instanciée, donc pas de constructeur.

Le cas d'utilisation que vous décrivez s'apparente à une classe abstraite dans laquelle le constructeur appelle une méthode d'une méthode abstraite implémentée dans une classe enfant.

Le problème inhérent ici est que pendant l'exécution du constructeur de base, l'objet enfant n'est pas encore construit et donc dans un état imprévisible.

Pour résumer: demande-t-il des problèmes lorsque vous appelez des méthodes surchargées à partir de constructeurs parents, pour citer mindprod :

En général, vous devez éviter d'appeler des méthodes non finales dans un constructeur. Le problème est que l'initialisation d'instance/initialisation de variable dans la classe dérivée est effectuée après le constructeur de la classe de base.

11
rsp

Il n'y a que des champs statiques dans l'interface qui n'ont pas besoin d'être initialisés lors de la création d'objet dans la sous-classe et la méthode d'interface doit fournir l'implémentation réelle dans la sous-classe. Donc, il n'y a pas besoin de constructeur dans l'interface.

Deuxième raison: lors de la création de l'objet par la sous-classe, le constructeur parent est appelé .Mais s'il y aura plus d'une interface implémentée, un conflit se produira lors de l'appel du constructeur de l'interface pour savoir quel constructeur d'interface appellera en premier.

4
Satyajit Gami

Pour contourner ce problème, définissez une méthode getInstance() dans votre interface afin que l’implémenteur sache quels paramètres doivent être gérés. Ce n'est pas aussi solide qu'une classe abstraite, mais cela permet plus de flexibilité que d'être une interface.

Toutefois, cette solution de contournement nécessite que vous utilisiez la getInstance() pour instancier tous les objets de cette interface.

Par exemple.

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

Les dépendances qui ne sont pas référencées dans une méthode d'interface doivent être considérées comme des détails d'implémentation, pas comme quelque chose que l'interface applique. Bien sûr, il peut y avoir des exceptions, mais en règle générale, vous devez définir votre interface comme le comportement attendu. L'état interne d'une implémentation donnée ne devrait pas être un problème de conception de l'interface.

2
Yishai

Si vous voulez vous assurer que chaque implémentation de l'interface contient un champ spécifique, il vous suffit d'ajouter à votre interface le getter pour ce champ :

interface IMyMessage(){
    @NonNull String getReceiver();
}
  • ça ne cassera pas l'encapsulation
  • il fera savoir à tous ceux qui utilisent votre interface que l'objet Receiver doit être passé à la classe d'une manière ou d'une autre (soit par constructeur, soit par setter)
2
Denys Vasylenko

Voir cette question pour le pourquoi (tiré des commentaires).

Si vous avez vraiment besoin de faire quelque chose comme ça, vous voudrez peut-être une classe de base abstraite plutôt qu'une interface.

1
JSBձոգչ

Ceci est dû au fait que les interfaces ne permettent pas de définir le corps de la méthode. Cependant, nous devrions définir le constructeur dans la même classe que les interfaces ont par défaut un modificateur abstrait pour toutes les méthodes à définir. C'est pourquoi nous ne pouvons pas définir de constructeur dans les interfaces.

1
Aasif Ali

Voici un exemple utilisant cette technique. Dans cet exemple spécifique, le code appelle Firebase à l'aide d'une fausse MyCompletionListener interface masquée en tant que classe abstraite, interface avec un constructeur.

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);
}
0
ExocetKid

Généralement, les constructeurs sont destinés à initialiser des membres non statiques d'une classe particulière par rapport à objet.

Il n'y a pas de création d'objet pour l'interface car il n'y a que des méthodes déclarées, mais pas des méthodes définies. Pourquoi ne pouvons-nous pas créer d’objet avec des méthodes déclarées? La création d’objet n’est rien d’autre que l’allocation de mémoire (dans la mémoire heap) pour des membres non statiques.

JVM créera de la mémoire pour les membres entièrement développés et prêts à être utilisés. Sur la base de ces membres, JVM calcule la quantité de mémoire requise pour ces membres et crée la mémoire.

En cas de méthodes déclarées, JVM est incapable de calculer la quantité de mémoire nécessaire à ces méthodes déclarées car l'implémentation sera effectuée dans le futur, ce qui n'est pas encore fait. donc la création d'objet n'est pas possible pour l'interface.

conclusion:

sans création d'objet, il n'y a aucune chance d'initialiser des membres non statiques via un constructeur.C'est pourquoi le constructeur n'est pas autorisé dans une interface (car il n'y a pas d'utilisation du constructeur dans une interface)

0
Sai Kumar