web-dev-qa-db-fra.com

Utilisation du paramètre qui implémente plusieurs interfaces pré-génériques

Supposons que j'ai ces interfaces:

public interface I1 {
  void foo();
}

public interface I2 {
  void bar();
}

et les classes:

public class A extends AParent implements I1, I2 {
   // code for foo and bar methods here
}

public class B extends BParent implements I1, I2 {
  // code for foo and bar methods here
}

public class C extends CParent implements I1 {
  // code for foo method here
}

Maintenant, avec des génériques, je peux avoir une méthode comme:

public <T extends I1 & I2> void method(T param) {
  param.foo();
  param.bar();
}

et je peux l'appeler avec A et B en tant que paramètres, mais pas avec C (il n'en mettant pas implémenter i2).

Y a-t-il eu un moyen d'atteindre ce type de générique de sécurité de type de type (Java <1.5).

Considérez que A, B et C ont des arbres d'héritage différents, et ce n'est pas vraiment une option de faire quelque chose comme un apart et un parent commun ayant un parent commun.

Je sais que tu pouvais faire:

public void method(I1 param) {
  param.foo();
  ((I2)param).bar();
}

mais alors vous pouvez également appeler method(new C()) qui ne met pas en œuvre i2, alors vous avez des problèmes.

Alors y a-t-il d'autres moyens que vous auriez pu faire cela?

P.s. : Je n'ai pas vraiment besoin de faire cela, c'est surtout par curiosité que je demande.

35

Créer une troisième interface I3 s'étend I1 et I2. Ensuite, la classe A et B implémentent I3 et la méthode générique accepte i3.

C'est peut-être le seul moyen de le faire.

26
Sripathi Krishnan

Je ne pense pas que les réponses ci-dessus sont bonnes sous le point de vue design. Lorsque vous faites une interface, vous souhaitez vous assurer que l'objet de l'appelant a responsabilité pour certaines actions définies dans cette interface. Il y a donc deux solutions discutant ci-dessus et je vais savoir pourquoi ces solutions ne sont pas bonnes dans le point de vue de la conception.

1. Faire une interface étend à la fois deux interfaces :

public interface IC extends IA,IB {
   // empty method here
}

Le code ci-dessus n'est pas sens. Vous définissez une interface distincte juste pour combiner d'autres interfaces et à l'intérieur, il n'y a aucune nouvelle méthode. Vous n'ajoutez aucune valeur à IC au lieu de combiner deux interface IA et IB. Et certaines situations, cette façon rendra votre code "peu amusant" lorsque vous ne trouvez pas le nom approprié pour la troisième interface. Cette situation conduira à un nom d'interface tel que IReadableAndWriteable ou ISomethingAndSomethingAndAnotherThing

2. TYPE CASTÉ INSIDE MÉTHODE :

public void methodA(IA object) {
   if (object instance of IB) {
     ((IB)(object)).someMethod()
}

De cette façon, c'est un non-sens aussi. Pourquoi le paramètre d'entrée est IA alors vous devez exécuter une action de l'interface IB? Sous point de vue programmeur, il n'ya aucun moyen de savoir que sauf de lire votre document. Ce n'est pas bon pour concevoir une fonction pour les autres personnes.

vraie solution :

Solutions ci-dessus Il y a un autre problème dans la conception: vous force programmeur Utilisez un objet qui a la responsabilité de deux interfaces. Quel est le problème si le programmeur ne veut pas faire cela. Ils veulent utiliser deux classes bétonnées différentes pour chaque différentes interfaces permettant de tester plus facilement, de nettoyer le code? ils ne peuvent pas.

Vous devez faire deux paramètres différents dans votre signature de méthode:

public void exampleMethod(IA object1, IB object2) {
   object1.someMethod()
   object2.someMethod()
}

Et pour appeler la méthode ci-dessus, vous mettez le même paramètre à l'intérieur (si le programmateur utilise le même objet). Ils peuvent également mettre également des objets différents.

public void caller() {
   IC object3 = new C(); // C is the class implements both IA and IB
   exampleMethod(object3, object3);
   IA objectA = new A();
   IB objectB = new B();
   exampleMethod(objectA, objectB);       
}

J'espère que cette aide :)

13
hqt

SRI est la meilleure réponse si vous aviez la permission de modifier la signature de A et B. Toutefois, si vous n'avez pas eu la permission, vous auriez pu faire:

public void method(I1 param1 , I2 param2) { // unpopular classes that do not implement I3 must use this method
  param1.foo();
  param2.bar();
}
public void method(I3 param){ // I hope everybody implements I3 when appropriate
  param.foo();
  param.bar();
}
public void method(A param){// A is a popular class
  method(param,param);
}
public void method(B param){// B is a popular class
  method(param,param);
}

Bien sûr, maintenant utilisez simplement des génériques.

2
emory

Avant Java 1.5 Il n'y a aucune solution pour atteindre ce type de sécurité au moment de la compilation. Mais il existe une solution au moment de l'exécution à l'aide de "Instanceof".

public void method(Object o) {
  if (!(o instanceof I1))
    throw new RuntimeException("o is not instance of I1");

  if (!(o instanceof I2))
    throw new RuntimeException("o is not instance of I2");

  // go ahead ...
}
2
BraincompilerLC