Composants de découplage
En MVC, vous avez une relation triangulaire entre les composants. C'est-à-dire : Le contrôleur possède la vue et le modèle. La vue repose sur la définition du modèle. Le modèle doit répondre aux exigences de la vue. Pensez à une architecture en étoile (contrôleur) et en rayons (vue et modèle).
Dans MVVM, pensez à ce triangle qui s'aplatit, chaque composant ne connaissant qu'un seul autre élément de la chaîne. C'est-à-dire : Vue->VueModèle->Modèle
Le modèle n'est pas au courant de ce qui se passe en haut de la pile. Le ViewModel ne connaît que le Model. La vue n'est consciente que du modèle de vue - elle n'est pas consciente du modèle.
Pourquoi est-ce important ?
C'est le cœur de la question initiale.
L'objectif principal est de poursuivre l'abstraction de votre architecture. Cela conduit généralement à un peu plus de code, mais à moins de points de contact entre les objets. La réduction des points de contact est importante, car elle permet d'obtenir un code plus agile. Plus la classe A est couplée ou en contact avec la classe B, plus l'impact d'un changement dans la classe A sera important. Réduire l'impact du changement est l'un des principaux avantages d'une bonne architecture.
Pour bien comprendre, il est utile de réfléchir à ce que les composants représentent réellement. Qu'est-ce qu'une vue, un contrôleur, un ViewModel ou un modèle ? S'agit-il de définitions littérales ou plutôt d'un concept abstrait ?
D'après mon expérience, il est plus avantageux de considérer le modèle comme un ensemble de classes/objets qui traitent de la construction et de la persistance des données. Ce n'est pas un simple objet avec des propriétés. C'est une classe qui récupère et sauvegarde les données, une usine qui construit des objets ordinaires. C'est une couche de façade qui fournit une API claire pour les données. Cette couche de façade doit-elle être référencée directement à partir de la vue ?
À mon avis, il ne devrait pas. En MVC, la réponse est également "non". Le contrôleur va chercher les données dans le modèle. À cet égard, MVC et MVVM atteignent le même objectif. Là où les deux architectures diffèrent, c'est dans la manière dont les données et la vue sont liées.
Comme le modèle, la vue peut être une collection de classes qui, en coordination les unes avec les autres, rendent une vue de présentation. Cela peut consister en un contrôleur de vue + une vue dans le cas des plateformes mobiles (contrôleur de vue sur iOS, activité sur Android). Dans de nombreux cas, vous avez besoin d'une classe pour charger un document de vue en mémoire et mettre à jour les propriétés de la vue. Il y a beaucoup de travail à faire ici. En MVC, le contrôleur devient rapidement une classe "évier de cuisine" - une sorte de décharge pour tout ce qui concerne le contexte actuel de l'utilisateur.
Si vous multipliez cela par des dizaines de vues potentielles au sein de votre application, vous vous retrouvez avec un grand nombre de dépendances profondes entre votre code de modèle back-end et votre code de vue front-end. Avec les grandes classes de contrôleur, ces dépendances ne sont pas immédiatement apparentes.
Aplanir vos dépendances
MVVM aplatit les dépendances. Cela crée la focalisation. Qu'est-ce que la concentration ? La capacité de travailler sur un seul élément de fonctionnalité sans être distrait par toutes les autres dépendances. Vous pouvez maintenant commencer à écrire des tests unitaires sur du code qui était auparavant considéré comme impossible à tester.
Le modèle de vue agit comme une façade entre la vue et le modèle. Le View Model répond aux besoins de la vue - techniquement, la vue devrait posséder le View Model. Si la vue a besoin de données provenant de plusieurs sources, le View Model encapsule la composition de sources de données distinctes dans un objet unique, unifié et dé-normalisé. Si la vue doit faire appel au modèle ou à d'autres destinations, le modèle de vue fournit des crochets et achemine l'appel approprié.
Voyez comment fonctionne un panneau de raccordement de réseau. À première vue, cela semble redondant - pourquoi ne pas simplement câbler votre réseau Ethernet du point A au point B. Mais avec l'expérience, vous comprendrez qu'un panneau de brassage vous fournit une pièce d'abstraction clé qui vous permet de modifier les routes du point B sans affecter le point A. C'est ce que fait votre modèle de vue.
Maintenant que vous avez une abstraction propre entre votre vue et votre modèle, la conséquence devrait être que votre vue/contrôleur ne s'occupe que de la présentation. Cela signifie qu'il ne devrait pas s'occuper de la localisation ou du formatage - il obtient des données et les présente. Votre modèle de vue est l'endroit idéal pour effectuer ce type de traitement des données avant la présentation. Disons que vous avez besoin de filtrer les données en fonction d'un critère. Encore une fois, le modèle de vue connaît les données du modèle (votre vue ne les connaît pas) et c'est l'endroit idéal pour mettre ce genre de code.
Une fois que vous commencez à organiser les exigences de votre application de cette manière, votre code de vue/contrôleur devient plus propre, et lorsque quelque chose doit être modifié, les implications sont plus évidentes, ce qui conduit à moins de bogues.
Testabilité
Une dernière remarque sur la testabilité : En aplatissant les dépendances, il est plus facile d'injecter des dépendances fictives dans vos tests. Cela rend les tests plus faciles et plus concis. Votre modèle de vue devient quelque chose contre lequel vous pouvez définir des cas de test clairs.