Si j'ai deux interfaces, toutes deux assez différentes dans leurs objectifs, mais avec la même signature de méthode, comment faire pour qu'une classe implémente les deux sans être obligé d'écrire une seule méthode qui sert pour les deux interfaces et d'écrire une logique alambiquée dans la méthode implémentation qui vérifie pour quel type d'objet l'appel est effectué et appelle le code approprié?
En C #, cela est surmonté par ce que l'on appelle une implémentation d'interface explicite. Existe-t-il un moyen équivalent en Java?
Réponses:
Non, il n'y a aucun moyen d'implémenter la même méthode de deux manières différentes dans une classe en Java.
Cela peut conduire à de nombreuses situations déroutantes, c'est pourquoi Java l'a interdit.
Ce que vous pouvez faire est de composer une classe à partir de deux classes qui implémentent chacune une interface différente. Ensuite, cette classe aura le comportement des deux interfaces.
la source
ISomething1 CompositeClass.asInterface1();
etISomething2 CompositeClass.asInterface2();
à cette classe. Ensuite, vous pouvez simplement extraire l'un ou l'autre de la classe composite. Il n'y a cependant pas de grande solution à ce problème.public long getCountAsLong() implements interface2.getCount {...}
[au cas où l'interface requiert unlong
mais les utilisateurs de la classe s'attendentint
] ouprivate void AddStub(T newObj) implements coolectionInterface.Add
[en supposant qu'ilcollectionInterface
existe unecanAdd()
méthode, et pour toutes les instances de cette classe, elle retournefalse
]?Il n'y a pas vraiment de moyen de résoudre ce problème en Java. Vous pouvez utiliser des classes internes comme solution de contournement:
Bien que cela ne permette pas les conversions de
AlfaBeta
àBeta
, les downcasts sont généralement mauvais, et si l'on peut s'attendre à ce qu'uneAlfa
instance ait souvent unBeta
aspect aussi, et pour une raison quelconque (généralement l'optimisation est la seule raison valable), vous voulez pouvoir pour le convertirBeta
, vous pouvez créer une sous-interfaceAlfa
avecBeta asBeta()
dedans.la source
Si vous rencontrez ce problème, c'est probablement parce que vous utilisez l' héritage là où vous devriez utiliser la délégation . Si vous devez fournir deux interfaces différentes, bien que similaires, pour le même modèle de données sous-jacent, vous devez utiliser une vue pour fournir à moindre coût l'accès aux données à l'aide d'une autre interface.
Pour donner un exemple concret pour ce dernier cas, supposons que vous souhaitiez implémenter à la fois
Collection
etMyCollection
(qui n'hérite pas deCollection
et possède une interface incompatible). Vous pouvez fournir des fonctionsCollection getCollectionView()
etMyCollection getMyCollectionView()
qui fournissent une implémentation légère deCollection
etMyCollection
, en utilisant les mêmes données sous-jacentes.Pour le premier cas ... supposons que vous vouliez vraiment un tableau d'entiers et un tableau de chaînes. Au lieu d'hériter des deux
List<Integer>
etList<String>
, vous devriez avoir un membre de typeList<Integer>
et un autre membre de typeList<String>
, et faire référence à ces membres, plutôt que d'essayer d'hériter des deux. Même si vous n'aviez besoin que d'une liste d'entiers, il est préférable d'utiliser la composition / délégation sur l'héritage dans ce cas.la source
Le problème Java "classique" affecte également mon développement Android ...
La raison semble simple:
plus de frameworks / bibliothèques que vous devez utiliser, plus facilement les choses peuvent être hors de contrôle ...
Dans mon cas, j'ai une classe BootStrapperApp hérité de android.app.Application ,
alors que la même classe devrait également implémenter une interface Platform d'un framework MVVM afin de s'intégrer.
Une collision de méthode s'est produite sur une méthode getString () , qui est annoncée par les deux interfaces et devrait avoir une implémentation de différenet dans différents contextes.
La solution de contournement (moche..IMO) utilise une classe interne pour implémenter tous plates-formesméthodes, juste à cause d'un conflit mineur de signature de méthode ... dans certains cas, une telle méthode empruntée n'est même pas utilisée du tout (mais a affecté la sémantique de conception majeure).
J'ai tendance à convenir que l'indication de contexte / espace de noms explicite de style C # est utile.
la source
La seule solution qui m'est venue à l'esprit consiste à utiliser des objets de référence à celui que vous souhaitez implémenter de multiples interfaces.
ex: en supposant que vous ayez 2 interfaces à implémenter
et
vous pouvez les inclure dans deux objets Facador:
et
En fin de compte, la classe que vous vouliez devrait quelque chose comme
vous pouvez maintenant utiliser les méthodes getAs * pour "exposer" votre classe
la source
Vous pouvez utiliser un modèle d'adaptateur pour les faire fonctionner. Créez deux adaptateurs pour chaque interface et utilisez-les. Cela devrait résoudre le problème.
la source
Tout va bien lorsque vous avez un contrôle total sur tout le code en question et que vous pouvez l'implémenter dès le départ. Imaginez maintenant que vous avez une classe publique existante utilisée dans de nombreux endroits avec une méthode
Maintenant, vous devez le passer dans le WizzBangProcessor standard qui nécessite des classes pour implémenter le WBPInterface ... qui a également une méthode getName (), mais au lieu de votre implémentation concrète, cette interface s'attend à ce que la méthode renvoie le nom d'un type de Wizz Bang Processing.
En C # ce serait un trvial
Dans Java Tough, vous allez devoir identifier chaque point dans la base de code déployée existante où vous devez convertir d'une interface à l'autre. Bien sûr, la société WizzBangProcessor aurait dû utiliser getWizzBangProcessName (), mais ce sont aussi des développeurs. Dans leur contexte, getName était bien. En fait, en dehors de Java, la plupart des autres langages basés sur OO le prennent en charge. Java est rare en forçant toutes les interfaces à être implémentées avec la même méthode NAME.
La plupart des autres langages ont un compilateur qui est plus qu'heureux de prendre une instruction pour dire "cette méthode dans cette classe qui correspond à la signature de cette méthode dans cette interface implémentée est son implémentation". Après tout, le but de la définition des interfaces est de permettre à la définition d'être abstraite de l'implémentation. (Ne me lancez même pas sur les méthodes par défaut dans les interfaces en Java, et encore moins sur le remplacement par défaut ... parce que bien sûr, chaque composant conçu pour une voiture de route devrait pouvoir être claqué dans une voiture volante et juste fonctionner - hé ce sont deux voitures ... Je suis sûr que la fonctionnalité par défaut de dire que votre GPS ne sera pas affectée par les entrées par défaut de tangage et de roulis, car les voitures ne font que lacer!
la source