Modèle MVC sur Android


497

Est-il possible d'implémenter le modèle de modèle-vue-contrôleur dans Java pour Android?

Ou est-il déjà mis en œuvre par le biais des activités? Ou existe-t-il une meilleure façon de mettre en œuvre le modèle MVC pour Android?


64
Votre question est très bonne. Mais la réponse marquée comme solution n'est pas correcte à mon avis. Cela pourrait induire en erreur plusieurs personnes.
Saghar

4
Consultez mes 2 articles commençant ici Architecture Android: MV?
Dori

1
Y a-t-il également un ensemble supplémentaire de règles à suivre pour adhérer à MVC ou le développement Android est-il déjà adapté à MVC en raison de l'activité, du XML, des ressources?
Flamme d'udun

3
@ Dori, je corrige votre lien: Architecture Android: MV?
Andreybeta

Cet article correspond exactement à ce que vous recherchez, MVC dans Android à travers un exemple pratique: digigene.com/architecture/android-architecture-part-2-mvc
Ali Nem

Réponses:


239

Dans Android, vous n'avez pas MVC, mais vous disposez des éléments suivants:

  • Vous définissez votre interface utilisateur dans différents fichiers XML par résolution, matériel, etc.
  • Vous définissez vos ressources dans divers fichiers XML par paramètres régionaux, etc.
  • Vous étendez des classes comme ListActivity , TabActivity et utilisez le fichier XML par des inflaters .
  • Vous pouvez créer autant de classes que vous le souhaitez pour votre logique métier.
  • Beaucoup d' Utils ont déjà été écrits pour vous - DatabaseUtils, Html.

3
@JDPekham, pourquoi dites-vous "Vous ne pouvez pas instancier une activité sans parler à votre mise en page / vue"? Instancier une activité ne nécessite pas de parler aux vues, en fait, parler aux vues ne fait en aucun cas partie de l'instanciation de l'activité. Vous POUVEZ (mais n'êtes pas obligé) d'appeler diverses méthodes d'activité qui interagissent avec vos vues quand et si vous le souhaitez. Deuxième question: en supposant que l'activité est destinée à jouer le rôle de "contrôleur" (je crois que de nombreux développeurs Android le voient de cette façon), pourquoi ne pas parler de votre point de vue sur l'activité?

8
Pour tous ceux qui disent que "Android est MVC", essayez Backbone.js (oui, js côté client) pendant une semaine, puis revenez et dites que "Android est MVC". Vous comprendrez enfin la question et pourquoi nous continuons à poser :)
Mark Peterson

14
"Dans Android, vous n'avez pas de MVC" ???? Dans Android, comme dans d'autres langues, vous avez MVC si vous voulez MVC.
Lorenzo Barbagli

1
@LorenzoBarbagli Il signifie qu'Android n'applique pas MVC dans les applications par conception (comme le fait iOS). Vous devez implémenter vous-même une version de MVC, MVP ou autre chose si vous voulez réaliser ce que MVC fournit - à savoir la séparation des préoccupations et un modèle isolé et facilement testable.
Piovezan

Non. Il y a certainement MVC dans Android, mais plus implicitement. Il est simplement implémenté d'une manière différente selon la façon dont Android structure tout.
6rchid

229

Il n'y a pas de modèle MVC universel unique. MVC est un concept plutôt qu'un cadre de programmation solide. Vous pouvez implémenter votre propre MVC sur n'importe quelle plate-forme. Tant que vous vous en tenez à l'idée de base suivante, vous implémentez MVC:

  • Modèle: quoi rendre
  • Vue: comment rendre
  • Contrôleur: événements, entrée utilisateur

Pensez-y également de cette façon: lorsque vous programmez votre modèle, le modèle ne devrait pas avoir à se soucier du rendu (ou du code spécifique à la plate-forme). Le modèle dirait à la vue, je me fiche que votre rendu soit Android ou iOS ou Windows Phone, c'est ce que j'ai besoin que vous rendiez. La vue ne gérerait que le code de rendu spécifique à la plate-forme.

Cela est particulièrement utile lorsque vous utilisez Mono pour partager le modèle afin de développer des applications multiplates-formes.


12
Bien que ce soit vrai et bien dit, c'est de la théorie et les gens sont pratiques!
TWiStErRob

1
@TWiStErRob Mais les modèles de conception sont des idées théoriques et abstraites qui n'ont pas qu'une seule façon de les réaliser. Proclamer «Je ne veux pas comprendre le MVC en théorie, je veux juste le mettre en œuvre» me semble que cela pourrait entraîner «Je vais mettre une machine à laver dans ma cuisine parce que les machines à laver mettent en œuvre le modèle Cleaner ™ et les cuisines en ont besoin ».
Lukas Juhrich

1
Je pense que les exemples sont inestimables car ils montrent ce que les autres ont pensé. On peut les améliorer et apprendre de leurs efforts. Pas besoin que tout le monde réinvente la roue. Dans le contexte d'Android et de son cycle de vie complexe, il y a des problèmes qui ne sont pas traités dans un modèle de conception, mais tout le monde y sera confronté. C'est ce que je voulais dire par pratique.
TWiStErRob

47

Les actions, vues et activités sur Android sont la manière intégrée de travailler avec l'interface utilisateur Android et sont une implémentation du modèle modèle-vue-vue-modèle (MVVM) , qui est structurellement similaire (dans la même famille que) modèle-vue -manette.

À ma connaissance, il n'y a aucun moyen de sortir de ce modèle. Cela peut probablement être fait, mais vous perdrez probablement tous les avantages du modèle existant et devrez réécrire votre propre couche d'interface utilisateur pour le faire fonctionner.


29

Après quelques recherches, la réponse la plus raisonnable est la suivante:

MVC est déjà implémenté dans Android en tant que:

  1. View = disposition, ressources et classes intégrées comme Buttondérivées de android.view.View.
  2. Contrôleur = Activité
  3. Modèle = les classes qui implémentent la logique d'application

(Cela n'implique d'ailleurs aucune logique de domaine d'application dans l'activité.)

La chose la plus raisonnable pour un petit développeur est de suivre ce modèle et de ne pas essayer de faire ce que Google a décidé de ne pas faire.

PS Notez que l'activité est parfois redémarrée, il n'y a donc pas de place pour les données du modèle (le moyen le plus simple de provoquer un redémarrage est d'omettre android:configChanges="keyboardHidden|orientation"du XML et de tourner votre appareil).

ÉDITER

On peut parler de MVC , mais ce sera pour ainsi dire FMVC , Framework - Model - View - Controller . Le Framework (le système d'exploitation Android) impose son idée du cycle de vie des composants et des événements associés, et dans la pratique, le Controller ( Activity/ Service/ BroadcastReceiver) est tout d'abord responsable de faire face à ces événements imposés par le Framework (comme onCreate () ). L'entrée utilisateur doit-elle être traitée séparément? Même si c'est le cas, vous ne pouvez pas le séparer, les événements d'entrée utilisateur proviennent également d'Android.

Quoi qu'il en soit, moins vous mettez de code non spécifique à Android dans votre Activity/ Service/ BroadcastReceiver, mieux c'est.


3
L'activité a un accès direct à l'interface utilisateur, tandis que dans MVC, le contrôleur ne devrait pas connaître la vue (seulement vice versa).
Konrad Morawski

2
@KonradMorawski Hmmm .... Une vue connaissant l'affichage des choses et sur le contrôleur ? Un enfant de, disons, Buttonconnaître le contrôleur ? Il semble plus logique que les vues ne connaissent que l'affichage des choses. Et compte tenu du fait que le modèle ne connaît que la nature des données, c'est pourquoi le contrôleur est nécessaire: quelque chose doit connaître à la fois le modèle et la vue .
18446744073709551615

4
De toute évidence, la vue doit connaître le contrôleur afin de déléguer des événements au contrôleur. Le contrôleur le suit jusqu'au modèle et informe la Vue quels étaient les résultats (afin qu'il puisse les afficher). Le contrôleur ne gonfle pas la vue (contrairement à Activity) et ne doit rien savoir des boutons, des zones de texte, des listes, etc. (alors que Activity sait).
Konrad Morawski

1
Je pense que je suis également Servicesous le contrôle du contrôleur
CL22

1
Avez-vous déjà entendu parler d'observateurs? La meilleure séparation Iv trouvée jusqu'à présent est lorsque 1. le contrôleur n'a qu'une instance de modèle, 2. le modèle n'a aucune connaissance du contrôleur ou de la vue mais la vue peut s'enregistrer en tant qu'observateur de modèle (donc le modèle connaît un peu la vue mais il ne sait pas qui c'est et il ne se soucie pas) - lorsque le modèle est terminé avec le chargement des données, il avertit tous les observateurs (généralement 1) et 3. la vue n'a qu'une instance de modèle pour en extraire les données. De cette façon, il n'y a que 2 dépendances pour tous les frameworks MVC. Je pense que 2 est minimum, donc ce devrait être la meilleure mise en page.
Srneczek

18

Il n'y a aucun modèle MVC auquel vous pourriez obéir. MVC indique simplement plus ou moins que vous ne devez pas mélanger les données et les vues, de sorte que, par exemple, les vues sont responsables de la conservation des données ou des classes qui traitent les données affectent directement la vue.

Mais néanmoins, la façon dont Android gère les classes et les ressources, vous êtes même parfois obligé de suivre le modèle MVC. Plus compliquées à mon avis sont les activités qui sont parfois responsables de la vue, mais qui agissent néanmoins en même temps comme contrôleur.

Si vous définissez vos vues et mises en page dans les fichiers XML, chargez vos ressources à partir du dossier res et si vous évitez plus ou moins de mélanger ces choses dans votre code, vous suivez de toute façon un modèle MVC.


14

Vous pouvez implémenter MVC dans Android, mais il n'est pas "pris en charge nativement" et demande un certain effort.

Cela dit, je tends personnellement vers MVP comme un modèle architectural beaucoup plus propre pour le développement Android. Et en disant MVP, je veux dire ceci:

entrez la description de l'image ici

J'ai également posté une réponse plus détaillée ici .

Après avoir joué avec les différentes approches de la mise en œuvre MVC / MVP dans Android, j'ai trouvé un modèle architectural raisonnable, que j'ai décrit dans un article: MVP et MVC Architectural Patterns dans Android .


14

La meilleure ressource que j'ai trouvée pour implémenter MVC sur Android est ce post :

J'ai suivi la même conception pour l'un de mes projets, et cela a très bien fonctionné. Je suis un débutant sur Android, donc je ne peux pas dire que c'est la meilleure solution.

J'ai fait une modification: j'ai instancié le modèle et le contrôleur pour chaque activité de la classe d'application afin qu'ils ne soient pas recréés lorsque le mode paysage-portrait change.


8
serait formidable d'obtenir un résumé au cas où l'article serait supprimé un jour.
pqsk

12

Je suis d'accord avec JDPeckham et je pense que XML seul n'est pas suffisant pour implémenter la partie UI d'une application.

Cependant, si vous considérez l'activité comme faisant partie de la vue, l'implémentation de MVC est assez simple. Vous pouvez remplacer Application (comme retourné par getApplication () dans Activity) et c'est ici que vous pouvez créer un contrôleur qui survit pendant la durée de vie de votre application.

(Vous pouvez également utiliser le modèle singleton comme suggéré par la documentation de l'application)


12

MVC-Architecture sur Android Il vaut mieux suivre n'importe quel MVP à la place de MVC dans Android. Mais toujours selon la réponse à la question, cela peut être une solution

Entrez la description de l'image ici

Description et directives

     Controller -
        Activity can play the role.
        Use an application class to write the
        global methods and define, and avoid
        static variables in the controller label
    Model -
        Entity like - user, Product, and Customer class.
    View -
        XML layout files.
    ViewModel -
        Class with like CartItem and owner
        models with multiple class properties
    Service -
        DataService- All the tables which have logic
        to get the data to bind the models - UserTable,
        CustomerTable
        NetworkService - Service logic binds the
        logic with network call - Login Service
Helpers -
        StringHelper, ValidationHelper static
        methods for helping format and validation code.
SharedView - fragmets or shared views from the code
        can be separated here

AppConstant -
        Use the Values folder XML files
        for constant app level

NOTE 1:

Maintenant, voici le morceau de magie que vous pouvez faire. Une fois que vous avez classé le morceau de code, écrivez une classe d'interface de base comme IEntity et IService. Déclarez les méthodes courantes. Créez maintenant la classe abstraite BaseService et déclarez votre propre ensemble de méthodes et séparez le code.

REMARQUE 2: Si votre activité présente plusieurs modèles, plutôt que d'écrire le code / la logique dans l'activité, il est préférable de diviser les vues en fragments. Alors c'est mieux. Donc, à l'avenir, si plus de modèle est nécessaire pour apparaître dans la vue, ajoutez un autre fragment.

NOTE 3: La séparation du code est très importante. Chaque composant de l'architecture doit être indépendant et ne pas avoir de logique dépendante. Si par hasard si vous avez quelque chose de logique dépendante, écrivez une classe logique de mappage entre les deux. Cela vous aidera à l'avenir.



9

Le modèle MVC d'Android est (en quelque sorte) implémenté avec leurs classes d' adaptateurs . Ils remplacent un contrôleur par un «adaptateur». La description de l'adaptateur indique:

Un objet Adapter agit comme un pont entre un AdapterView et les données sous-jacentes pour cette vue.

Je cherche juste une application Android qui lit à partir d'une base de données, donc je ne sais pas encore comment cela fonctionne. Cependant, cela ressemble un peu à l'architecture Model-View-Delegate de Qt, qui, selon eux, est une avancée par rapport à un modèle MVC traditionnel. Au moins sur le PC, le modèle de Qt fonctionne assez bien.


9

Bien que cet article semble être ancien, j'aimerais ajouter les deux suivants pour informer sur le développement récent dans ce domaine pour Android:

android-binding - Fournit un cadre qui permet la liaison des widgets de vue android au modèle de données. Il aide à implémenter des modèles MVC ou MVVM dans les applications Android.

roboguice - RoboGuice élimine les conjectures du développement. Injectez votre vue, ressource, service système ou tout autre objet et laissez RoboGuice s'occuper des détails.


9

Contrôleur de vue du modèle (MVC)

entrez la description de l'image ici


La description:

  • Lorsque nous devons gérer de grands projets dans le développement de logiciels, MVC est généralement utilisé parce que c'est une façon universelle d'organiser les projets.
  • Les nouveaux développeurs peuvent s'adapter rapidement au projet
  • Aide au développement de grands projets et multi-plateformes.

Le modèle MVC est essentiellement le suivant:

  • Modèle: quoi afficher. Cela peut être la source de données (Ex: serveur, données brutes dans l'application)
  • Voir: comment il est affiché. Cela peut être le xml. Il agit ainsi comme un filtre de présentation. Une vue est attachée à son modèle (ou pièce de modèle) et obtient les données nécessaires à la présentation.
  • Contrôleur: gestion des événements tels que l'entrée utilisateur. Ce sera l'activité

Fonctionnalité importante de MVC: nous pouvons modifier soit le modèle, soit la vue, soit le contrôleur sans affecter les autres

  • Disons que nous changeons la couleur de la vue, la taille de la vue ou la position de la vue. Ce faisant, cela n'affectera pas le modèle ou le contrôleur
  • Supposons que nous modifions le modèle (au lieu que les données extraites du serveur récupèrent les données des actifs), cela n'affectera pas la vue et le contrôleur
  • Disons que nous changeons le contrôleur (logique dans l'activité) cela n'affectera pas le modèle et la vue

2
Je n'ai jamais utilisé le contrôleur comme un conduit pour voir / modéliser les informations de relais. Je suis curieux de savoir comment vous avez un modèle et une vue en contact direct les uns avec les autres. Avez-vous une source ou un exemple de cette implémentation?
Jacksonkr

7

Je pense que l'explication simplifiée la plus utile est ici: http://www.cs.otago.ac.nz/cosc346/labs/COSC346-lab2.2up.pdf

D'après tout le reste que j'ai vu et lu ici, la mise en œuvre de toutes ces choses le rend plus difficile et ne s'intègre pas bien avec d'autres parties d'Android.

Avoir une activité implémenter d'autres écouteurs est déjà la manière standard d'Android. Le moyen le plus inoffensif serait d'ajouter Java Observer comme les diapositives décrivent et regroupent le onClick et d'autres types d'actions dans des fonctions qui sont toujours dans l'activité.

La manière Android est que l'activité fait les deux. Le combattre ne facilite pas vraiment l'extension ou le codage futur.

Je suis d'accord avec le 2ème post . C'est en quelque sorte déjà implémenté, mais pas comme les gens sont habitués. Que ce soit ou non dans le même fichier, il y a déjà une séparation. Il n'est pas nécessaire de créer une séparation supplémentaire pour l'adapter à d'autres langues et systèmes d'exploitation.


6
Le lien que vous avez fourni est rompu.
mmBs

6

Il était surprenant de voir qu'aucun des articles ici n'a répondu à la question. Ils sont soit trop généraux, vagues, incorrects ou ne traitent pas de l'implémentation dans Android.

Dans MVC, la couche View ne sait que montrer l'interface utilisateur (UI). Si des données sont nécessaires pour cela, elles les obtiennent de la couche Modèle . Mais la vue ne demande PAS directement au modèle de trouver les données, elle le fait via le contrôleur . Le contrôleur  appelle donc le modèle pour fournir les données requises pour la vue . Une fois les données prêtes, le contrôleur informe la vue que les données sont prêtes à être acquises à partir du modèle . Maintenant, la vue peut obtenir les données du modèle .

Ce flux peut être résumé comme suit:

entrez la description de l'image ici

Il convient de noter que la vue peut connaître la disponibilité des données dans le  modèle  via le contrôleur - également appelé  MVC passif - ou en observant les données dans le modèle en enregistrant des observables, qui est Active MVC .

En ce qui concerne l'implémentation, l'une des premières choses qui me vient à l'esprit est que quel composant Android doit être utilisé pour la vue ? Activity  ou Fragment ?

La réponse est que cela n'a pas d'importance et que les deux peuvent être utilisés. La vue doit être en mesure de présenter l'interface utilisateur (UI) sur l'appareil et de répondre à l'interaction de l'utilisateur avec l'interface utilisateur. Les deux Activity  et Fragment  fournissent les méthodes requises pour cela.

Dans l'exemple d'application utilisé dans cet article, j'ai utilisé Activity pour la couche View , mais Fragment  peut également être utilisé.

L'exemple d'application complet se trouve dans la branche «mvc» de mon dépôt GitHub ici .

J'ai également traité des avantages et des inconvénients de l'architecture MVC dans Android à travers un exemple ici .

Pour les personnes intéressées, j'ai commencé une série d'articles sur l'architecture des applications Android ici dans laquelle je compare les différentes architectures, à savoir MVC, MVP, MVVM, pour le développement d'applications Android via une application de travail complète.


J'ai suivi un cours d'architecture où l'instructeur déclare que les activités et les fragments ne doivent pas être utilisés comme vues et doivent en fait être des contrôleurs et que les vues doivent être des fichiers séparés. Avez-vous une opinion ou un raisonnement sur le fait que cela ne devrait pas être le cas?
brandonx

Je ne pense pas que l'instructeur soit exact à ce sujet. Choisir l'activité ou le fragment comme contrôleur signifie passer le contexte au contrôleur. D'un autre côté, la vue a également besoin de contexte pour dessiner à l'écran. De cette façon, c'est-à-dire en passant le contexte au contrôleur, l'application est sujette à une fuite de mémoire et je pense que le contrôleur ne devrait pas porter l'état.
Ali Nem

5

Étant fatigué du désastre MVx sur Android, j'ai récemment créé une petite bibliothèque qui fournit un flux de données unidirectionnel et est similaire au concept de MVC: https://github.com/zserge/anvil

Fondamentalement, vous avez un composant (activité, fragment et groupe de vues). À l'intérieur, vous définissez la structure et le style du calque de vue. Vous définissez également comment les données doivent être liées aux vues. Enfin, vous pouvez lier des auditeurs au même endroit.

Ensuite, une fois vos données modifiées - la méthode globale "render ()" sera appelée, et vos vues seront intelligemment mises à jour avec les données les plus récentes.

Voici un exemple du composant ayant tout à l'intérieur pour la compacité du code (bien sûr, le modèle et le contrôleur peuvent être facilement séparés). Ici, "count" est un modèle, la méthode view () est une vue et "v -> count ++" est un contrôleur qui écoute les clics sur le bouton et met à jour le modèle.

public MyView extends RenderableView {
  public MyView(Context c) {
      super(c);
  }

  private int count = 0;

  public void view() {
    frameLayout(() -> {              // Define your view hierarchy
      size(FILL, WRAP);
      button(() -> {
          textColor(Color.RED);      // Define view style
          text("Clicked " + count);  // Bind data
          onClick(v -> count++);     // Bind listeners
      });
    });
  }

Avec le modèle et le contrôleur séparés, cela ressemblerait à:

button(() -> {
   textColor(Color.RED);
   text("Clicked " + mModel.getClickCount());
   onClick(mController::onButtonClicked);
});

Ici, à chaque clic sur le bouton, le nombre sera augmenté, puis "render ()" sera appelé et le texte du bouton sera mis à jour.

La syntaxe devient plus agréable si vous utilisez Kotlin: http://zserge.com/blog/anvil-kotlin.html . En outre, il existe une syntaxe alternative pour Java sans lambdas.

La bibliothèque elle-même est très légère, n'a aucune dépendance, n'utilise aucune réflexion, etc.

(Avertissement: je suis l'auteur de cette bibliothèque)


4

Selon l'explication que l'équipe Xamarin a expliquée (sur le MVC iOS "je sais que ça semble bizarre, mais attendez une seconde"):

  • Le modèle (données ou logique d'application),
  • La vue (interface utilisateur), et
  • Le contrôleur (code derrière).

Je peux dire ceci:

Le modèle sur Android est simplement l'objet parcellable. La vue est la disposition XML et le contrôleur est le (activité + son fragment).

* Ceci est juste mon opinion, pas d'une ressource ou d'un livre.



3

J'ai vu que beaucoup de gens disent que MVC est déjà implémenté dans Android, mais ce n'est pas vrai. Android ne suit aucun MVC par défaut.

Parce que je ne sais pas, Google imposera jamais avec force les restrictions d'une implémentation MVC comme l'iPhone, mais c'est aux développeurs quels patteren ou technique ils veulent dans leur projet, dans de petites ou simples applications, l'utilisation de MVC n'est pas requise, mais comme application grandit et se complique et nécessite des modifications de son code dans les années suivantes, puis il y a un besoin du modèle MVC dans Android.

Il fournit un moyen simple de modifier le code et aide également à réduire les problèmes. Si vous souhaitez implémenter MVC sur Android, suivez ce lien ci-dessous et profitez de l'implémentation MVC dans votre projet.

http://www.therealjoshua.com/2011/11/android-architecture-part-1-intro/

Mais de nos jours, je pense que MVP avec Android Architectural Pattern est l'une des meilleures options que les développeurs devraient utiliser pour des applications Android propres et robustes.


1
D'accord. Android a suffisamment de flexibilité pour se pendre. Cette activité peut rapidement devenir gigantesque et compliquée car elle gère les trois aspects de MVC.
Scott Biggs

2

Lorsque nous appliquons MVC, MVVM ou un modèle de présentation à une application Android, ce que nous voulons vraiment, c'est avoir un projet structuré clair et, plus important encore, plus facile pour les tests unitaires.

Pour le moment, sans infrastructure tierce, vous avez généralement beaucoup de code (comme addXXListener (), findViewById (), etc.), qui n'ajoute aucune valeur commerciale.

De plus, vous devez exécuter des tests unitaires Android au lieu des tests JUnit normaux, qui prennent un certain temps à s'exécuter et rendent les tests unitaires peu pratiques. Pour ces raisons, il y a quelques années, nous avons lancé un projet open source, RoboBinding - Un cadre de modèle de présentation de liaison de données pour la plate-forme Android.

RoboBinding vous aide à écrire du code d'interface utilisateur plus facile à lire, à tester et à maintenir. RoboBinding supprime le besoin de code inutile comme addXXListener ou ainsi , et déplace la logique de l'interface utilisateur vers le modèle de présentation, qui est un POJO et peut être testé via des tests JUnit normaux . RoboBinding lui-même est livré avec plus de 300 tests JUnit pour garantir sa qualité.


1

À ma connaissance, la façon dont Android gère le modèle MVC est comme:

Vous avez une activité, qui sert de contrôleur. Vous avez une classe dont la responsabilité est d'obtenir les données - le modèle, puis vous avez la classe View qui est la vue.

Quand on parle de la vue, la plupart des gens ne pensent qu'à sa partie visuelle définie dans le xml. N'oublions pas que la Vue a aussi une partie programme avec ses constructeurs, méthodes et etc, définis dans la classe java.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.