cplanson / think-tank

4 stars 0 forks source link

Multi-héritage Java / Android #7

Open acadet opened 9 years ago

acadet commented 9 years ago

Je suis actuellement en train de faire du développement mobile. J'essaie de factoriser au maximum mon code au fur et à mesure. Ainsi, je factorise un header, un footer ou un outil facilitant la gestion des formulaires de mon application.

Néanmoins, toutes ces ressources nécessitent un accès aux données des activités Android (en particulier le contexte). La première idée qui m'est venue est alors de faire hériter mon activité courante d'une autre (qui serait une base) que j'ai également crée, comme par exemple HeaderActivity (activité ayant un header).

Mais voilà, j'aimerais ensuite créé une activité ayant un formulaire et un header. Or il existe des activités ayant uniquement des formulaires. Il m'est donc impossible de faire hériter FormActivity de HeaderActivity.

La seule solution que j'ai trouvé à ce jour est de considérer ces éléments comme des modules à part, et chaque activité se crée des liens-a-un vers les modules désirés.

En réfléchissant à ce problème, j'ai tout de suite pensé au pattern décorateur (une activité header-form, activité header etc.). Malheureusement, il est incapable de répondre à mon problème ici, vu que je ne possède pas d'interface(s) commune(s).

Ma question est alors la suivante : y a-t-il un moyen de s'approcher du multi-héritage en Java ? Ou des mixins ? S'il existe une solution complètement différente pour pallier à mon problème, je suis également intéressé !

FoxCie commented 9 years ago

Oui, c'est à travers des interfaces plutôt qu'un héritage de classes. C'est un choix de Java, C++ permet de faire du vrai multi-héritage, mais c'est assez galère dès qu'on a des méthodes qui ont le même nom, d'où le choix fait par Java.

Je connais pas les design-patterns, donc je vais juste répondre avec ce dont je me souviens des cours de POO de Georgy (qui étaient bien quand on comprenait ce qu'il voulait en fait) : soit tu fais des interfaces, mais tu risques d'avoir de la duplication de code si tu te contentes de faire ça, soit tu bosses avec des liens a-un qui sont des implémentations de classes abstraites (ou concrètes, peu importe). Je pense que le mieux d'un point de vue conceptuel c'est de faire des interfaces, et des classes abstraites qui les implémentent. Si tu veux faire un Header qui soit un Form, je pense que tu dois faire une classe abstraite AbstractHeaderForm qui hérite de AbstractHeader (ou AbstractForm, à toi de choisir) et implémente FormInterface (ou HeaderInterface donc, selon ton choix). Là, il faudrait faire un lien a-un dans ta classe abstraite pour simuler l'héritage avec ton interface, mais le problème qui se pose c'est que tu as du coup besoin d'une classe concrète implémentant ton interface (à moins que tu ne puisses te contenter d'une classe anonyme).

À ma connaissance, pour simuler de l'héritage multiple en Java, il n'y a pas trente-six moyens : tu fais des interfaces, et tu fais des classes abstraites qui héritent d'une classe, et font proxy avec des liens a-un pour les autres héritages souhaités.

C'est une réponse un peu générale, et qui ne t'apprendra probablement rien, mais l'héritage multiple en Java ça n'existe volontairement pas, le truc qui s'en rapproche le plus c'est l'implémentation d'interfaces, donc après on se débrouille comme on peut avec ces contraintes. Ou alors on fait du C++ (je sais que tu fais du dev Android, mais on peut faire des applis natives avec C++ pour Android). Du coup, je me cite, parce que j'aime bien les auto-références : "Java, c'est de la merde" :) .

acadet commented 9 years ago

Merci pour ta réponse Matthieu.

Penses tu qu'il y aurait un moyen d'éviter de créer une classe HeaderForm, une HeaderFooterForm etc. ? Car cette méthode suivrait une loi factorielle si on venait à ajouter des modules supplémentaires.

Jette un oeil au pattern décorateur (sur Wikipédia, l'article est très bien fait), cela te donnera peut être des idées.

FoxCie commented 9 years ago

Je crois que j'ai trouvé ce que tu cherches : http://developer.android.com/guide/components/fragments.html

Il y a une méthode getActivity(), et ça me semble correspondre exactement à ce que tu cherches à faire. Je trouvais ça un peu bizarre, parce que tu faisais des activités comme des modules alors qu'en fait tu ne peux avoir qu'une activité active à la fois, du coup j'ai cherché si y avait pas quelque chose de plus adapté pour faire des trucs plus modulaires, et il semblerait qu'ils se soient rendu compte qu'avoir seulement des activités c'était un peu rigide comme truc, surtout pour un truc POO, donc ils ont fait ça. Les Fragments c'est en gros des sous-activités qui peuvent être réutilisées (des sortes de modules), autrement dit un truc autonome avec toute sa boucle MVC que tu peux mettre dans des Activity.

Je ne sais pas si c'est ce que tu cherches, mais tel que je l'ai compris, ton problème c'est que t'essayais de faire des modules comprenant toute la chaine MVC, mais jusqu'à la version 3.0 d'Android il n'y avait, je crois, que les Activity qui permettait de faire Controller, ce qui limite beaucoup la modularité vu que tu ne peux en avoir qu'une d'active à la fois. Depuis la 3.0 ils ont rajouté Fragment parce que quand même, ne pas pouvoir inclure de Controller dans les modules, c'est quand même sacrément idiot (pourquoi on te permet de faire des View modulaires, de les arranger comme tu veux avec des Layouts, mais pas de leur associer de Controller ? Ils auraient pu y penser plus tôt je trouve, mais bon...)

Je pense que ce truc est vraiment adapté à ton problème, après je n'ai pas lu la totalité de la page de description ; en tout cas, ce n'est pas, je pense, le rôle des Activity, ce qui explique que tu galères à les utiliser comme ça.

acadet commented 9 years ago

Hé pas mal ça. En fait je connaissais déjà les fragments, mais je n'avais pas poussé assez loin mes recherches. Je ne savais pas qu'on pouvait les déclarer dans le XML surtout.

Je te remercie Matthieu :wink: ça va m'être grandement utile !

Néanmoins mon problème n'est pas tout à fait réglé :smile: On a réussi à résoudre la problématique de réutilisation d'un composant autonome, comme un header par exemple.

Mais que dire des modules exposant des méthodes factorisant le code ? Par exemple un module qui va permettre de traiter les champs d'un formulaire et d'afficher des erreurs à l'utilisateur ? D'un module affichant différent popups d'alertes selon les informations provenant des activités ?

FoxCie commented 9 years ago

Dans ce cas là, je dirais que j'ai répondu dans ma première réponse. T'as pas trente-six possibilités : tu fais un héritage, et si t'en as besoin de plusieurs, tu fais des interfaces et un lien a-un. Après, je pense que tu peux t'en sortir avec des héritages simples pour ça. Par exemple, pour les alertes ça m'a l'air typiquement d'être un truc qui va avoir une variable contenant le type de popup à afficher, et une méthode abstraite permettant d'afficher celle qui faut en fonction de ton activité (suffit de faire un fragment encore). Ton module qui traite des formulaires, ce sera juste un Fragment qui héritera de ton FormFragment je pense aussi, normalement tu devrais pas avoir de problème, ou alors j'ai pas bien compris où il se situe.