1

Bonjour,
j'aimerais passer en paramètre à une fonction un objet qui implémente les 3 interfaces suivantes:
HasMouseDownHandlers, HasMouseOverHandlers, HasMouseOutHandlers

J'ai essayé de faire une interface intermédiaire:

public interface CanHaveToolTip extends  HasMouseDownHandlers, HasMouseOverHandlers, HasMouseOutHandlers {
}


La fonction à appeller devient:

public void truc(CanHaveToolTip canHaveToolTip) { ... }

et je l'utilise de la manière suivante:

Label label = new Label(); //Label est une classe qui implémente 
//HasAllMouseHandlers, HasClickHandlers, HasMouseDownHandlers,
//HasMouseMoveHandlers, HasMouseOutHandlers, HasMouseOverHandlers, etc...
o.truc(label);


Mais ça ne compile pas sad (parceque Label n'implémente pas CanHaveToolTip, bien qu'il implémente (entre autre) les 3 interfaces de CanHaveToolTip.

Comment faire ?

2

Je dirais, repenser le design de ton code.
Je ne sais pas si ce sont tes vraies classes (si c'est le cas, je trouve ça attroce comme découpage; voir plus bas) mais en gros ce que tu fais ressemble à définir une interface pour chaque méthode, genre:
interface HasMethodA { } interface HasMethodB { } … Ce qui est complètement contre productif.
Du coup tu essayes d'utiliser une interface comme contrat implicite (alors que c'est en réalité un contrat explicite) afin de colmater ce raisonnement. (En fait tu essayes d'utiliser les interface de manière contradictoire. ^^)
Dans ton cas, on pourrait éventuellement s'accorder sur le fait que les clics et les survols soient catégorisables…
Mais après, il me semble logique que, par exemple, l'évènement « MouseDown » soit lié à l'évènement « MouseUp », de même que l'évènement « MouseHover » sera intrinsèquement lié à l'élément « MouseLeave » (et éventuellement l'évènement « MouseEnter », mais celui-ci est générable entièrement à partir des deux précédents). Donc tu n'aurais déjà que deux interfaces. « HandlesClick » et « HandlesHovering ». Et plus sérieusement tu devrais même n'avoir qu'une seule interface « HandlesMouse »… Car si ta classe ne fait pas usage des évènements de la souris, ce n'est pas important. Ce qui est important, c'est juste qu'elle soit capable de les recevoir. Tu auras plus de méthodes vides dans tes classes, mais ça sera beaucoup plus propre au niveau abstrait. tongue

Bref, supposons, que tu gardes une partie de ce design bridé, comme ça j'aborderai le second point, à savoir comment résoudre ce type de problème quand le design à côté n'est pas à revoir. (Quand tu mixes des interfaces qui n'ont rien en commum par exemple)
Dans ton cas, un tooltip requiert un ensemble de fonctionnalité minimal qui est le survol (hovering). Donc les deux évènements Hover et Leave / Out (peu importe comment tu veux les nommer, du moment que c'est suffisemment clair). En revanche (car je suis quand même où tu veux en venir tongue) il est évident, qu'avoir un clic pour désactiver le tooltip peut s'avérer utile. (D'où l'intérêt de gérer la souris comme une seule fonctionnalité => interface et pas comme 50 bouts de fonctionnalité)
Donc, tu demandes à l'utilisateur de la fonction de lui fournir un « HandlesHovering », donc tu pourras implémenter ton survol de manière fonctionnelle. Mais celà ne t'mpêche pas d'implémenter la fonctionnalité supplémentaire du tooltip qui depop au moment du clic si jamais la classe implémente aussi « HandlesClick » grâce au magnifique « instanceof ».

Enfin, je sais pas si j'ai été assez clair… J'espère. tongue
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

3

Ce sont les interfaces HasMouseDownHandlers, HasMouseOverHandlers et HasMouseOutHandlers qui devraient étendre l’interface CanHaveToolTip, pas l’inverse smile
(Et d’ailleurs cette interface ne devrait pas être vide, elle devrait au moins contenir les opérations communes à toutes ces interfaces, et qui permettent de manipuler la ToolTip)
avatar
« Quand le dernier arbre sera abattu, la dernière rivière empoisonnée, le dernier poisson capturé, alors vous découvrirez que l'argent ne se mange pas. »

4

Heu… non seulement tu inverses complètement la logique des interfaces, mais en plus ça ne résoud pas le problème… (mais alors pas du tout grin)
Dans ton raisonnement gérer "MouseDown" à lui seul impliquerait de gérer intégralement "Tooltip". Complètement illogique… tongue
Car du coup, implémenter CanHaveToolTip ne donne absolument aucune garantie sur l'objet et c'est complètement débile.
Mais il y a en effet une solution que j'ai oublié de mentionner, c'est d'utiliser object et de se débarasser de CanHaveToolTip… Ce qui ne rendra pas pour autant le code plus élégant, mais marchera sans modification.
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

5

En gros, ton problème est que tu essaies d'utiliser du Java comme du Python. Le Java ne fait pas le "duck typing". Tu peux éventuellement le simuler avec l'introspection, mais beurk! sick
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

6

./4 Ah, en fait j’avais compris qu’il voulait qu’un objet qui implémente au moins **une** des trois interfaces mentionnées soit considéré comme implémentant CanHaveToolTip.

Bah du coup, pourquoi ne pas faire implémenter l’interface CanHaveToolTip à la classe Label, plutôt que les trois ?
avatar
« Quand le dernier arbre sera abattu, la dernière rivière empoisonnée, le dernier poisson capturé, alors vous découvrirez que l'argent ne se mange pas. »

7

En fait Son interface CanHaveToolTip c'est un moyen pour lui de dire « un objet (n'importe lequel) qui implémente HasMouseDownHandlers, HasMouseOverHandlers et HasMouseOutHandlers ». Un contrat implicite comme on appelle ça… Donc quelque chose de plutôt dynamique en fait. (Donc nécéssité d'utiliser un de ces 3 types principalement, ou un de leurs ancêtres… ou Object)
Enfin, tout est dans mon post bla bla. Pour moi, c'est le design qui est en cause, mais ça peut aussi se régler de manière entièrement « dynamique » avec instanceof, throw, et des cast. sick (Mais bien entendu dans ce cas, on perd la vérification statique des types, donc c'est plutôt naze ^^)
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

8

Merci, vous avez bien analysé mon problème. Donc en gros il n'y pas moyen de vérifier statiquement qu'un objet implémente 3 interfaces sad
En y réfléchissant, c'est normal. J'ai bien fais de poser la question smile

9

En fait, ce que tu veux, c'est l'idée de concepts, mais malheureusement aucun langage de programmation standard ne les gère à ce moment. (C'était prévu pour le C++0x, mais ça a été retiré jusqu'à nouvel ordre.)
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

10

Intéressant, c'est effectivement de ça dont j'avais besoin smile

11

Kevin Kofler (./9) :
En fait, ce que tu veux, c'est l'idée de concepts, mais malheureusement aucun langage de programmation standard ne les gère à ce moment.
Et il y a des langages *non standards* qui les gèrent ?
avatar
« Quand le dernier arbre sera abattu, la dernière rivière empoisonnée, le dernier poisson capturé, alors vous découvrirez que l'argent ne se mange pas. »

12

Oh, je ne savais pas qu'il y avait du monde qui codait en GWT... je le trouve trop "saoulant" à coder...
Avant tout, il faut se poser la question "pourquoi veux-tu que l'objet passé en paramètre définisse les 3 interfaces ?"

Si le but est juste de pouvoir utiliser les méthodes des 3 interfaces, et vu que se sont des interfaces, justement, tu as le droit d'écrire :

public void truc (Object o) {
    Interface1 interf1 = (Interface1) o;
    Interface2 interf2 = (Interface2) o;
    Interface3 interf3 = (Interface3) o;

    interf1.method1();
    interf2.method2();
    ...
}


ire o.truc (new Label());Ainsi, tu pourras écr
Par contre, tu n'auras pas d'erreur de compilation, mais des erreurs de ClassCast si l'objet passé en paramètre n'est pas des bonnes interfaces...
Rest... In... Peace

13

Sasume > ça me semble assez difficile à implémenter concrètement, à moins d'avoir recours à de l'introspection. sorry
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

14

Quel est le problème ?
avatar
« Quand le dernier arbre sera abattu, la dernière rivière empoisonnée, le dernier poisson capturé, alors vous découvrirez que l'argent ne se mange pas. »

15

Sasume (./11) :
Et il y a des langages *non standards* qui les gèrent ?

ConceptC++, le langage géré par ConceptGCC. Mais ConceptGCC n'est plus activement développé, et l'intérêt général pour l'idée a diminué, depuis que la décision a été prise de ne pas inclure ça dans le C++0x. Décision qui avait pour motif l'absence d'implémentations indépendantes, ça sent un peu le problème de la poule et de l'œuf… sad
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

16

CoppeR (./12) :
Par contre, tu n'auras pas d'erreur de compilation, mais des erreurs de ClassCast si l'objet passé en paramètre n'est pas des bonnes interfaces...

Oui oui ça on sait smile mon but c'est de détecter les erreurs lors de la compilation (enfin qui est un problème résolu: on ne peut pas grin)

17

Tiens, juste pour info en Scala ça se fait très facilement smile
trait C1 {
  def foo(): Unit = println("foo")
}

trait C2 {
  def bar(): Unit = println("bar")
}

class D extends C1 with C2

object ConceptMain {
  type Concept = {
    def foo(): Unit
    def bar(): Unit
  }

  def useConcept(concept: Concept): Unit = {
    concept.foo()
    concept.bar()
  }

  def main(args: Array[String]): Unit = {
    val d = new D
    useConcept(d)
  }
}
avatar
« Quand le dernier arbre sera abattu, la dernière rivière empoisonnée, le dernier poisson capturé, alors vous découvrirez que l'argent ne se mange pas. »

18

Pour ceux que ça intéresse, une autre façon d’implémenter les Concepts en Scala : http://ropas.snu.ac.kr/~bruno/papers/TypeClasses.pdf
avatar
« Quand le dernier arbre sera abattu, la dernière rivière empoisonnée, le dernier poisson capturé, alors vous découvrirez que l'argent ne se mange pas. »