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, car 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érez la classe de message suivante:

public class MyMessage { public MyMessage(Ssortingng receiver) { this.receiver = receiver; } private Ssortingng receiver; public void send() { //some implementation for sending the mssage to the receiver } } 

Si vous définissez une interface pour cette classe afin que je puisse avoir plus de classes implémentant l’interface de message, je ne peux définir que la méthode d’envoi et non le constructeur. Alors, comment puis-je m’assurer que chaque implémentation de cette classe a bien un récepteur? Si j’utilise une méthode comme setReceiver(Ssortingng receiver) je ne suis pas sûr que cette méthode soit réellement appelée. Dans le constructeur, je pouvais l’assurer.

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 que je puisse avoir plus de classes qui implémentent l’interface de message, je ne peux définir que la méthode d’envoi et non le constructeur”

… ces exigences correspondent exactement à ce que sont les classes abstraites .

Un problème que vous obtenez lorsque vous autorisez les constructeurs dans les interfaces vient de la possibilité d’implémenter plusieurs interfaces en même temps. Lorsqu’une classe implémente plusieurs interfaces qui définissent différents constructeurs, la classe devrait implémenter plusieurs constructeurs, chacun ne satisfaisant qu’une interface, mais pas les autres. Il sera impossible de construire un object qui appelle chacun de ces constructeurs.

Ou en code:

 interface Named { Named(Ssortingng 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(Ssortingng name) { ... } /** implements HasList constructor. * This constructor should not be used from outside, * because Ssortingng 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(Ssortingng name, List list) { this(name); // the next line is illegal; you can only call one other super constructor this(list); } } 

Une interface définit un contrat pour une API, c’est-à-dire un ensemble de méthodes sur lesquelles les implémenteurs et les utilisateurs de l’API sont d’accord. 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 est que lorsque le constructeur de base est en cours d’exécution, l’object enfant n’est pas encore construit, et donc dans un état imprévisible.

Pour résumer: est-ce que cela pose problème lorsque vous appelez des méthodes surchargées 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 de l’instance / l’initialisation de la variable dans la classe dérivée est effectuée après le constructeur de la classe de base.

Il n’y a que des champs statiques dans l’interface qui n’ont pas besoin d’être initialisés pendant la création d’object dans la sous-classe et la méthode d’interface doit fournir une 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’object de la sous-classe, le constructeur parent est appelé. Mais si plusieurs interfaces sont implémentées, un conflit se produira lors de l’appel du constructeur de l’interface.

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, et non 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 en fonction du comportement attendu. L’état interne d’une implémentation donnée ne devrait pas être une préoccupation de conception de l’interface.

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

Si vous avez vraiment besoin de faire quelque chose comme cela, vous pouvez vouloir une classe de base abstraite plutôt qu’une interface.

En effet, les interfaces ne permettent pas de définir le corps de la méthode en elle-même. Mais il faudrait définir le constructeur dans la même classe car 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.

Un travail que vous pouvez essayer consiste à définir une méthode getInstance() dans votre interface afin que l’implémenteur sache quels parameters doivent être gérés. Ce n’est pas aussi solide qu’une classe abstraite, mais cela permet une plus grande flexibilité en tant qu’interface.

Toutefois, cette solution de contournement nécessite l’utilisation de getInstance() pour instancier tous les objects de cette interface.

Par exemple

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

Voici un exemple d’utilisation de cette technique. Dans cet exemple spécifique, le code effectue un appel à Firebase en utilisant un MyCompletionListener qui est une interface masquée en tant que classe abstraite, une interface avec un constructeur.

 private interface Listener { void onComplete(databaseError, databaseReference); } public abstract class MyCompletionListener implements Listener{ Ssortingng id; Ssortingng name; public MyCompletionListener(Ssortingng id, Ssortingng name) { this.id = id; this.name = name; } } private void removeUserPresenceOnCurrentItem() { mFirebase.removeValue(child("some_key"), new MyCompletionListener(UUID.randomUUID().toSsortingng(), "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); } 

Si vous voulez vous assurer que chaque implémentation de l’interface contient un champ spécifique, vous devez simplement append à votre interface le getter pour ce champ :

 interface IMyMessage(){ @NonNull Ssortingng getReceiver(); } 
  • il ne cassera pas l’encapsulation
  • il indiquera à tous ceux qui utilisent votre interface que l’object Receiver doit être transmis à la classe d’une manière ou d’une autre (soit par constructeur, soit par setter)

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

Il n’y a pas de création d’object pour l’interface car il n’y a que des méthodes déclarées mais pas des méthodes définies. Pourquoi nous ne pouvons pas créer d’object pour les méthodes déclarées La création de is-object n’est rien d’autre que l’allocation de mémoire (en mémoire de tas) pour les membres non statiques.

JVM créera de la mémoire pour les membres qui sont entièrement développés et prêts à être utilisés. Basé sur ces membres, JVM calcule la quantité de mémoire requirejse pour eux et crée de la mémoire.

En dehors des méthodes déclarées, JVM ne peut pas calculer la quantité de mémoire requirejse pour ces méthodes déclarées, car l’implémentation se fera à l’avenir, ce qui n’est pas le cas à ce stade. La création d’object n’est donc pas possible pour l’interface.

conclusion:

sans création d’object, 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 de constructeur dans une interface)