Dans cette vidéo de Rich Hickey , le créateur de Clojure, il conseille d'utiliser la carte pour représenter les données au lieu d'utiliser une classe pour les représenter, comme cela est fait en Java. Je ne comprends pas comment cela peut être mieux, car comment l'utilisateur de l'API peut-il savoir quelles sont les clés d'entrée si elles sont simplement représentées sous forme de cartes.
Exemple :
PersonAPI {
Person addPerson(Person obj);
Map<String, Object> addPerson(Map<String, Object> personMap);
}
Dans la deuxième fonction, comment l'utilisateur de l'API peut-il savoir quelles sont les entrées pour créer une personne?
Résumé exaggitif (TM)
Vous obtenez quelques choses.
Il y a un inconvénient fatal.
La chose est, vous pouvez obtenir l'introspection en utilisant, euh, l'introspection. C'est ce qui se produit généralement:
En d'autres termes, si vous n'avez jamais besoin d'interfacer avec FP, vous n'avez pas à suivre les conseils de Rich Hickey.
Dernier point, mais pas le moindre (ni le plus joli), bien que l'utilisation de String
comme clé de propriété soit la plus simple, vous n'avez pas besoin d'utiliser String
s. De nombreux systèmes hérités, y compris Android ™, utilisent largement les identifiants entiers dans l'ensemble du framework pour faire référence aux classes, propriétés, ressources, etc.
Android est une marque déposée de Google Inc.
Vous pouvez également rendre les deux mondes heureux.
Pour le monde Java, implémentez les getters et setters comme d'habitude.
Pour le monde FP, implémentez le
Object getPropertyByName(String name)
void setPropertyByName(String name, Object value) throws IllegalPropertyChangeException
List<String> getPropertyNames()
Class<?> getPropertyValueClass(String name)
À l'intérieur de ces fonctions, oui, du code laid, mais il y a IDE plugins qui le rempliront pour vous, en utilisant ... euh, un plugin intelligent qui lit votre code.
Le côté Java des choses sera aussi performant que d'habitude. Ils n'utiliseront jamais cette partie laide du code. Vous pourriez même vouloir pour le cacher à Javadoc.
Le côté FP du monde peut écrire le code "leet" qu'il veut, et il ne vous crie généralement pas que le code est lent.
En général, l'utilisation d'une carte (sac de propriété) à la place d'un objet est courante dans le développement de logiciels. Il n'est pas unique à la programmation fonctionnelle ou à tout type de langage particulier. Ce n'est peut-être pas une approche idiomatique pour une langue donnée, mais certaines situations l'exigent.
En particulier, la sérialisation/désérialisation nécessite souvent une technique similaire.
Juste quelques réflexions générales concernant la "carte comme objet".
C'est un excellent discours de quelqu'un qui sait vraiment de quoi il parle. Je recommande aux lecteurs de regarder le tout. Cela ne dure que 36 minutes.
Un de ses principaux points est que la simplicité ouvre plus tard des opportunités de changement. Le choix d'une classe pour représenter un Person
offre l'avantage immédiat de créer une API statiquement vérifiable, comme vous l'avez souligné, mais cela vient avec le coût de limiter les opportunités ou d'augmenter les coûts de changement et de réutilisation ultérieurement.
Son point de vue est que l'utilisation de la classe peut être un choix raisonnable, mais cela devrait être un choix conscient qui vient avec une pleine conscience de son coût, et les programmeurs font traditionnellement un très mauvais travail de remarquer ces coûts, sans parler de les prendre en considération. Ce choix doit être réévalué à mesure que vos besoins augmentent.
Voici quelques changements de code (dont un ou deux ont été mentionnés dans l'exposé) qui sont potentiellement plus simples à l'aide d'une liste de mappages par rapport à l'utilisation d'une liste d'objets Person
:
Map
de primitives dans un format transmissible est hautement réutilisable et peut même être fournie dans une bibliothèque. A Person
objet aura probablement besoin de code personnalisé pour accomplir le même travail).Nous résolvons ces types de problèmes tout le temps et avons des modèles et des outils pour eux, mais nous nous arrêtons rarement pour penser si le choix d'une représentation de données plus simple et plus flexible au début aurait facilité notre travail.
Si les données ont peu ou pas de comportement, avec un contenu flexible susceptible de changer, utilisez une carte. L'OMI, un "javabean" ou "objet de données" typique qui se compose d'un modèle de domaine anémique avec N champs, N setters et N getters, est une perte de temps. N'essayez pas d'impressionner les autres avec votre structure glorifiée en l'enveloppant dans une classe de fantaisie. Soyez honnête, expliquez clairement vos intentions , et utilisez une carte. (Ou, si cela a un sens pour votre domaine, un objet JSON ou XML)
Si les données ont un comportement réel significatif, a.k.a méthodes ( Tell, Don't Ask ), puis utilisez une classe. Et tapotez-vous dans le dos pour utiliser une vraie programmation orientée objet :-).
Si les données ont beaucoup de comportement de validation essentiel et des champs obligatoires, utilisez une classe.
Si les données ont un comportement de validation modéré, c'est limite.
Si les données déclenchent des événements de changement de propriété, c'est en fait plus facile et beaucoup moins fastidieux avec une carte. Écrivez simplement une petite sous-classe.
Un inconvénient principal de l'utilisation d'une carte est que l'utilisateur doit convertir les valeurs en chaînes, en entiers, en faux, etc. Si cela est très ennuyeux et sujet aux erreurs, envisagez une classe. Ou considérez une classe d'aide qui enveloppe la carte avec les getters appropriés.
L'API pour un map
a deux niveaux.
L'API peut être décrite dans la carte par convention. Par exemple, la paire :api api-validate
peut être placé sur la carte ou :api-foo validate-foo
pourrait être la convention. La carte peut même stocker api api-documentation-link
.
L'utilisation de conventions permet au programmeur de créer un langage spécifique au domaine qui standardise l'accès à travers les "types" mis en œuvre sous forme de cartes. En utilisant (keys map)
permet de déterminer les propriétés lors de l'exécution.
Il n'y a rien de magique dans les cartes et il n'y a rien de magique dans les objets. Tout est expédié.