
Je travaille dans une entreprise de développement de jeux, mais comme passe-temps à la maison, je me suis récemment intéressé au développement d'applications mobiles. Par conséquent, lorsqu'un ami m'a invité à une réunion consacrée au développement d'applications mobiles utilisant le framework Flutter, j'ai accepté avec plaisir. Ayant essayé Flutter en action là-bas, j'ai décidé d'étudier définitivement cette technologie. Étant donné que le Dart nécessaire au développement ne m'était pas familier, l'apprentissage des langues était également inclus dans le programme obligatoire. Après m'être un peu penché sur les exemples de code, j'ai trouvé que Dart était un langage facile à comprendre et concis que j'aimais beaucoup. L'une des caractéristiques de Dart que j'ai aimé, ce sont les impuretés.
Quelles sont les impuretés?
Pour une première connaissance, je vais donner un
extrait de Wikipédia .
Le mélange (mixage anglais) est un élément d'un langage de programmation (généralement une classe ou un module) qui implémente un comportement clairement défini. Utilisé pour clarifier le comportement d'autres classes, non destiné à générer des objets utilisés indépendamment.
Dans Dart, ces constructions sont définies par le mot
mixin avant le nom.
La définition ci-dessus signifie que nous obtenons la fonctionnalité de comportements logiquement isolés qui peuvent être ajoutés à d'autres classes.
Cela vous rappelle-t-il la possibilité d'héritage multiple? Oui, mais il me semble que l'approche des impuretés est meilleure. Et pourquoi, regardons un exemple.
Supposons que nous ayons une classe abstraite Animal.
abstract class Animal { void voice(); }
Et aussi les classes Chat et Chien qui implémentent la classe Animal.
class Cat extends Animal { void voice() { print(“Meow”); } } class Dog extends Animal { void voice() { print(“Woof”); } }
Et puis nous avons soudainement eu besoin de ... Oui, oui, personnellement, je n'ai pas de telles choses pendant le développement.
Et dans le cas de l'héritage multiple, nous ferions de même.
class CatDog extends Cat, Dog { }
Mais dès que nous exprimons notre commande vocale à notre animal de compagnie, nous obtenons une situation très désagréable - on ne sait pas exactement à quoi il doit répondre, car la méthode
vocale est mise en œuvre dans les deux classes. Cette situation est largement connue et est appelée
le problème du diamant ou
diamant mortel de la mort .
Dans le cas de ventes par impuretés, nous ne le rencontrerons pas.
lass Animal { void voice() { print(“Hakuna Matata!”); } } mixin Cat { void voice() { print(“Meow”); } } mixin Dog { void voice() { print(“Woof”); } } class CatDog extends Animal with Cat, Dog { }
Et qu'entendrons-nous si nous donnons maintenant une commande vocale? Dans ce cas - Woof, et comme vous l'avez déjà compris, cela dépend de l'ordre d'addition des impuretés. Cela se produit car leur ajout n'est pas parallèle, mais séquentiel.
J'ai implémenté la classe Animal spécifiquement pour marquer une fonctionnalité introduite dans
Dart 2.1 . Avant cela, les impuretés ne pouvaient être ajoutées qu'aux classes héritant d'
Object . À partir de la version 2.1, l'ajout de toutes les classes aux héritiers est implémenté.
Ce mécanisme rend très pratique la création et l'utilisation des parties communes de la fonctionnalité, ce qui résout le problème de duplication de code. Regardons un exemple.
abstract class Sportsman { void readySteadyGo(); } mixin SkiRunner { void run() { print(“Ski, ski, ski”); } } mixin RifleShooter { void shot() { print(“Pew, pew, pew”); } } class Shooter() extends Sportsman with RifleShooter { void readySteadyGo() { shot(); } } class Skier() extends Sportsman with SkiRunner { void readySteadyGo() { run(); } } class Biathlete() extends Sportsman with SkiRunner, RifleShooter { void readySteadyGo() { run(); shot(); } }
Comme vous pouvez le voir, nous avons distribué tout le code en double par impuretés et n'avons utilisé que les nécessaires dans chacune des implémentations.
Pendant le développement, une situation peut survenir lorsque la fonctionnalité de l'une des impuretés ne doit pas être accessible au public pour être incluse par toutes les classes. Et un mécanisme qui nous permettra d'imposer ces restrictions est également disponible. Il s'agit du mot clé on dans la déclaration de mélange avec le nom de la classe. Nous limiterons donc l'utilisation des impuretés uniquement aux classes qui implémentent le spécifié ou hérité de celui-ci.
Par exemple:
class A { } abstract class B { } mixin M1 on A { } mixin M2 on B { }
Ensuite, nous pouvons déclarer des classes similaires:
class C extends A with M1 { } class D implements B with M2 { }
Mais nous obtenons une erreur en essayant de déclarer quelque chose comme ceci:
class E with M1, M2 { }
Utilisation dans l'application Flutter
Comme je l'ai mentionné ci-dessus, les impuretés vous permettent de vous débarrasser de la duplication de code et de créer des parties logiques distinctes qui peuvent être réutilisées. Mais comment est-ce généralement applicable à Flutter, où tout est atomique et donc divisé en widgets qui sont responsables d'une certaine fonctionnalité? À titre d'exemple, j'ai immédiatement imaginé une situation dans laquelle le projet utilise de nombreux widgets, dont l'affichage varie en fonction d'un certain état interne. Je vais considérer cet exemple dans l'architecture BLoC et utiliser des entités de la bibliothèque rxDart.
Nous avons besoin d'une interface pour fermer le contrôleur de débit.
Un mélange avec lequel nous mettons en œuvre le soutien de l'État.
La partie logique qui contrôlera l'état du widget. Laissez-la définir un état en appelant la méthode et après 3 secondes, changez-la en une autre.
Et le widget lui-même qui répondra à un changement d'état. Imaginez obtenir le composant logique souhaité à l'aide de l'injection de dépendance.
class ExampleWidget extends StatelessWidget { final bloc = di<HomePageBloc>(); @override Widget build(BuildContext context) { return StreamBuilder( stream: bloc.stateOut, builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
Si vous le souhaitez, nous pouvons même ajouter au mix ce qui est écrit et ne nécessiter que l'implémentation de la méthode du générateur en utilisant l'interface, mais il me semble que cela est déjà inutile, car il est peu probable qu'il y ait beaucoup de widgets simples dans le projet, car ce n'était qu'un exemple. Néanmoins, la partie logique de la fonction de support d'état sera facilement ajoutée à n'importe lequel des BLoC utilisant ce mélange.
Conclusion
Le mécanisme d'utilisation des impuretés m'a paru un outil de développement assez intéressant et flexible, qui permet de construire une architecture simple, compréhensible et pratique. Pour ma part, j'ai décidé que cet outil de mon kit ne serait évidemment pas superflu, j'espère qu'il vous sera utile aussi.
Ressources:
Une visite de la langue des fléchettesWikipédia