Je suis en train d’obtenir ma tête autour des objets immuables vs mutables. À l’aide d’objets mutables reçoit beaucoup de mauvaise presse (par exemple en retournant un tableau de chaînes d’une méthode), mais je ne parviens pas à comprendre ce que les impacts négatifs sont de cela. Quelles sont les meilleures pratiques autour de l’utilisation des objets mutables ? Vous évitez d’eux lorsque c’est possible ?
Réponses
Trop de publicités?Eh bien, il ya un couple des aspects de cette. Numéro un, mutable objets sans référence à l'identité peut provoquer des bugs à des moments étranges. Par exemple, considérons un Person
bean avec une valeur-basé equals
méthode:
Map<Person, String> map = ...
Person p = new Person();
map.put(p, "Hey, there!");
p.setName("Daniel");
map.get(p); // => null
L' Person
instance de se "perdre" dans la carte lorsqu'il est utilisé comme une clé car c'est hashCode
et de l'égalité ont été basés sur des valeurs mutables. Ces valeurs changé en dehors de la carte et tout le hachage est devenu obsolète. Des théoriciens comme à la harpe sur ce point, mais dans la pratique je n'ai pas trouvé ça trop un problème.
Un autre aspect est la logique de "caractère raisonnable" de votre code. C'est un dur à terme à définir, englobant tout, de la lisibilité à l'écoulement. De façon générique, vous devriez être en mesure de regarder un morceau de code et de comprendre facilement ce qu'il fait. Mais plus important que cela, vous devriez être capable de vous convaincre que c'est ce qu'il fait correctement. Lorsque les objets peuvent changer de façon indépendante à travers les différents code "domaines", il devient parfois difficile de garder une trace de ce qui est où et pourquoi ("spooky action at a distance"). C'est un concept difficile à illustrer, mais c'est quelque chose qui est souvent confronté à de plus grandes, plus complexes architectures.
Enfin, mutable objets sont killer dans des situations simultanées. Chaque fois que vous accédez à une mutable objet à partir de plusieurs threads, vous avez à traiter avec verrouillage. Cela réduit le débit et rend votre code considérablement plus difficile à maintenir. Suffisamment système compliqué coups ce problème jusqu'à présent hors de proportion qu'il devient presque impossible de maintenir (et même à la simultanéité des experts).
Des objets immuables (et plus particulièrement, immuable collections) éviter tous ces problèmes. Une fois que vous obtenir votre esprit autour de la façon dont ils fonctionnent, votre code sera développer en quelque chose qui est plus facile à lire, facile à entretenir et moins susceptibles d'échouer dans d'étranges et imprévisibles. Des objets immuables sont même plus facile à tester, en raison non seulement de leur facile mockability, mais aussi les modèles de code, ils ont tendance à appliquer. En bref, ils sont de bonne pratique à tous les étages!
Cela dit, je ne suis pas un zélote dans cette affaire. Certains problèmes il suffit de ne pas le modèle bien quand tout est immuable. Mais je ne pense que vous devriez essayer de pousser autant de votre code dans cette direction que possible, en supposant bien sûr que vous êtes en utilisant un langage qui fait d'elle une opinion défendable (C/C++ rend cela très difficile, tout comme Java). En bref: les avantages varier en fonction de votre problème, mais j'aurais tendance à préférer l'immuabilité.
Des Objets immuables vs Immuable Collections
L'un des points les plus fins dans le débat sur mutable contre des objets immuables, c'est la possibilité d'étendre le principe de l'immutabilité des collections. Immuable objet est un objet qui représente souvent une seule structure logique des données (par exemple immuable de la chaîne). Lorsque vous avez une référence à un objet immuable, le contenu de l'objet ne change pas.
Est immuable de la collection est une collection qui ne change jamais.
Lorsque j'effectue une opération sur une mutable collection, puis-je changer la collecte en place, et toutes les entités qui ont des références de la collection voir le changement.
Lorsque j'effectue une opération sur un immuable de la collection, une référence est renvoyée à une nouvelle collection reflétant le changement. Toutes les entités qui ont des références aux précédentes versions de la collection ne va pas voir le changement.
Intelligent mises en œuvre n'ont pas nécessairement besoin de copie (clone) à l'ensemble de la collection, afin de vous fournir l'immuabilité. L'exemple le plus simple est la pile mise en œuvre comme une seule liste, et le push/pop opérations. Vous pouvez réutiliser tous les nœuds de la précédente collection, dans la nouvelle collection, l'ajout d'un seul nœud pour le pousser, et le clonage pas de noeuds pour la pop. Le push_tail opération sur une seule liste liée, d'autre part, n'est pas aussi simple et efficace.
Immuable vs Mutable variables/références
Certains langages fonctionnels prendre le concept de l'immuabilité de références à des objets eux-mêmes, ne permettant qu'une seule référence de la mission.
- En Erlang c'est vrai pour toutes les "variables". Je peux seulement affecter des objets à la fois. Si je ont été de fonctionner sur une collection, je ne serais pas en mesure de réaffecter la nouvelle collection à l'ancienne référence (nom de variable).
- Scala s'appuie également présent dans la langue avec toutes les références en cours de déclarer avec var ou val, vals-les-bains n'étant unique, l'affectation et la promotion d'un style fonctionnel, mais vars, permettant un plus c ou java-comme la structure du programme.
- La var/val déclaration est requise, alors que beaucoup de langues traditionnelles en option modificateurs tels que final en java et const en c.
Facilité de Développement et de Performances
Presque toujours la raison de l'utilisation d'un immuable objet est de promouvoir les effets secondaires de la programmation gratuite et simple raisonnement sur le code (en particulier dans un très simultanée/environnement parallèle). Vous n'avez pas à vous soucier de données sous-jacentes d'être changé par une autre entité si l'objet est immuable.
Le principal inconvénient est la performance. Voici une écriture-up sur un simple test que j'ai fait en Java comparant certains immuable vs mutable objets dans un jouet problème.
Les problèmes de performances sont discutable dans de nombreuses applications, mais pas tous, c'est pourquoi beaucoup de grandes numérique paquets, comme le Tableau Numpy classe en Python, qui permettent de Placer les mises à jour de tableaux de grande taille. Ce serait important pour les domaines d'application qui font usage de la grande matrice et le vecteur des opérations. Ces grandes données parallèles et de calcul intensif des problèmes d'atteindre une grande vitesse par exploitation en place.
Des objets immuables sont un concept très puissant. Ils enlèvent beaucoup de la charge d'essayer de garder les objets/variables uniformes pour tous les clients.
Vous pouvez les utiliser pour les bas niveau, non polymorphes des objets comme un CPoint classe - qui sont principalement utilisés avec une valeur sémantique.
Ou vous pouvez les utiliser pour de haut niveau, polymorphe interfaces - comme un IFunction représentant une fonction mathématique - qui est utilisé exclusivement avec l'objet de la sémantique.
Le plus grand avantage : l'immuabilité + objet sémantique + pointeurs intelligents rend propriétaire de l'objet en un point discutable. Implicitement, cela signifie aussi déterministe du comportement en présence de la concurrence.
Inconvénient : lorsqu'il est utilisé avec des objets contenant beaucoup de données, la consommation de mémoire peut devenir un problème. Une solution pourrait être de maintenir les opérations sur un objet symbolique, et de faire l'évaluation différée. Cependant, cela peut conduire à des chaînes de calculs symboliques, qui peuvent avoir une influence négative sur les performances, si l'interface n'est pas conçu pour accueillir symbolique des opérations. Quelque chose à absolument éviter dans ce cas, est de retour d'énormes morceaux de la mémoire à partir d'une méthode. En combinaison avec enchaîné symbolique des opérations cela pourrait conduire à massive de la consommation de la mémoire et de la dégradation des performances.
Si des objets immuables sont certainement ma première façon de penser à propos de la conception orientée objet, mais ils ne sont pas un dogme. Ils résoudre beaucoup de problèmes pour les clients des objets, mais aussi de créer de nombreux, en particulier pour la mise en œuvre.
Consultez ce blog post: http://www.yegor256.com/2014/06/09/objects-should-be-immutable.html. Il explique pourquoi des objets immuables sont mieux que mutable. En bref:
- des objets immuables sont plus simples à construire, tester et utiliser
- vraiment des objets immuables sont toujours thread-safe
- ils aident à éviter le couplage temporel
- leur utilisation est sans effets secondaires (pas de défensive copies)
- l'identité de la mutabilité problème est évité
- ils ont toujours l'échec atomicité
- ils sont beaucoup plus faciles à mettre en cache
Vous devez spécifier quelle langue vous parlez. Pour les langages de bas niveau comme C ou C++, je préfère utiliser des objets mutables pour économiser de l’espace et réduire la perte de mémoire. Dans langues de plus haut niveau, des objets immuables facilitent à raisonner sur le comportement du code (en particulier le code multithread) parce qu’il n’y a aucun « spooky action à distance ».