J'essaie de comprendre les objets mutables vs immuables. L'utilisation d'objets mutables reçoit beaucoup de mauvaise presse (par exemple, le retour d'un tableau de chaînes à partir d'une méthode) mais j'ai du mal à comprendre quels sont les impacts négatifs de cela. Quelles sont les meilleures pratiques en matière d’utilisation d’objets mutables? Devriez-vous les éviter autant que possible?
oop
immutability
mutable
Alex Angas
la source
la source
string
est immuable, du moins en .NET, et je pense également dans de nombreux autres langages modernes.Réponses:
Eh bien, il y a quelques aspects à cela.
Les objets mutables sans identité de référence peuvent provoquer des bogues à des moments impairs. Par exemple, considérons un
Person
bean avec uneequals
méthode basée sur la valeur :L'
Person
instance est «perdue» dans la carte lorsqu'elle est utilisée comme clé car sonhashCode
égalité et son égalité sont basées sur des valeurs modifiables. Ces valeurs ont changé en dehors de la carte et tout le hachage est devenu obsolète. Les théoriciens aiment insister sur ce point, mais en pratique, je n'ai pas trouvé que c'était trop un problème.Un autre aspect est la "raison" logique de votre code. C'est un terme difficile à définir, englobant tout, de la lisibilité au flux. De manière générale, vous devriez être capable de regarder un morceau de code et de comprendre facilement ce qu'il fait. Mais plus important que cela, vous devriez être en mesure de vous convaincre qu'il fait ce qu'il fait correctement . Lorsque les objets peuvent changer indépendamment dans différents «domaines» de code, il devient parfois difficile de garder une trace de ce qui est où et pourquoi (« action effrayante à distance »). C'est un concept plus difficile à illustrer, mais c'est quelque chose que l'on rencontre souvent dans des architectures plus grandes et plus complexes.
Enfin, les objets mutables sont tueurs dans des situations simultanées. Chaque fois que vous accédez à un objet mutable à partir de threads séparés, vous devez gérer le verrouillage. Cela réduit le débit et rend votre code beaucoup plus difficile à maintenir. Un système suffisamment compliqué rend ce problème tellement disproportionné qu'il devient presque impossible à maintenir (même pour les experts de la concurrence).
Les objets immuables (et plus particulièrement les collections immuables) évitent tous ces problèmes. Une fois que vous aurez compris comment ils fonctionnent, votre code deviendra quelque chose de plus facile à lire, plus facile à maintenir et moins susceptible d'échouer de manière étrange et imprévisible. Les objets immuables sont encore plus faciles à tester, non seulement en raison de leur facilité de simulation, mais également des modèles de code qu'ils ont tendance à appliquer. Bref, ce sont de bonnes pratiques partout!
Cela dit, je ne suis guère un fanatique dans ce domaine. Certains problèmes ne sont tout simplement pas bien modélisés lorsque tout est immuable. Mais je pense que vous devriez essayer de pousser autant de code que possible dans cette direction, en supposant bien sûr que vous utilisez un langage qui en fait une opinion défendable (C / C ++ rend cela très difficile, tout comme Java) . Bref: les avantages dépendent un peu de votre problème, mais j'aurais tendance à préférer l'immuabilité.
la source
Objets immuables et collections immuables
L'un des points les plus fins du débat sur les objets mutables et immuables est la possibilité d'étendre le concept d'immuabilité aux collections. Un objet immuable est un objet qui représente souvent une seule structure logique de données (par exemple une chaîne immuable). Lorsque vous avez une référence à un objet immuable, le contenu de l'objet ne changera pas.
Une collection immuable est une collection qui ne change jamais.
Lorsque j'effectue une opération sur une collection mutable, je change la collection en place et toutes les entités qui ont des références à la collection verront le changement.
Lorsque j'effectue une opération sur une collection immuable, une référence est renvoyée à une nouvelle collection reflétant la modification. Toutes les entités qui ont des références à des versions précédentes de la collection ne verront pas la modification.
Les implémentations intelligentes n'ont pas nécessairement besoin de copier (cloner) la collection entière pour fournir cette immuabilité. L'exemple le plus simple est la pile implémentée sous forme de liste chaînée unique et les opérations push / pop. Vous pouvez réutiliser tous les nœuds de la collection précédente dans la nouvelle collection, en ajoutant un seul nœud pour le push et en ne clonant aucun nœud pour le pop. L'opération push_tail sur une seule liste chaînée, par contre, n'est pas si simple ou efficace.
Variables / références immuables vs mutables
Certains langages fonctionnels prennent le concept d'immuabilité aux références d'objets elles-mêmes, n'autorisant qu'une seule affectation de référence.
Facilité de développement vs performances
Presque toujours, la raison d'utiliser un objet immuable est de promouvoir une programmation sans effets secondaires et un raisonnement simple sur le code (en particulier dans un environnement hautement concurrent / parallèle). Vous n'avez pas à vous soucier de la modification des données sous-jacentes par une autre entité si l'objet est immuable.
Le principal inconvénient est la performance. Voici un article sur un test simple que j'ai effectué en Java comparant des objets immuables et mutables dans un problème de jouet.
Les problèmes de performances sont sans objet dans de nombreuses applications, mais pas dans toutes, c'est pourquoi de nombreux packages numériques volumineux, tels que la classe Numpy Array en Python, permettent des mises à jour sur place de grands tableaux. Cela serait important pour les domaines d'application qui utilisent de grandes opérations matricielles et vectorielles. Ces gros problèmes de parallélisme de données et de calcul intensif atteignent une grande accélération en fonctionnant sur place.
la source
Consultez ce billet de blog: http://www.yegor256.com/2014/06/09/objects-should-be-immutable.html . Cela explique pourquoi les objets immuables sont meilleurs que mutables. En bref:
la source
Les objets immuables sont un concept très puissant. Ils enlèvent une grande partie du fardeau d'essayer de garder les objets / variables cohérents pour tous les clients.
Vous pouvez les utiliser pour des objets non polymorphes de bas niveau - comme une classe CPoint - qui sont principalement utilisés avec la sémantique des valeurs.
Ou vous pouvez les utiliser pour des interfaces polymorphes de haut niveau - comme une IFonction représentant une fonction mathématique - qui est utilisée exclusivement avec la sémantique des objets.
Plus grand avantage: l'immuabilité + la sémantique des objets + les pointeurs intelligents font que la propriété de l'objet n'est pas un problème, tous les clients de l'objet ont leur propre copie privée par défaut. Implicitement, cela signifie également un comportement déterministe en présence de 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 à cela pourrait être de garder les opérations sur un objet symboliques et de faire une évaluation paresseuse. Cependant, cela peut alors conduire à des chaînes de calculs symboliques, qui peuvent avoir une influence négative sur les performances si l'interface n'est pas conçue pour accueillir des opérations symboliques. Dans ce cas, il faut absolument éviter de renvoyer d'énormes morceaux de mémoire à partir d'une méthode. En combinaison avec des opérations symboliques chaînées, cela pourrait entraîner une consommation de mémoire massive et une dégradation des performances.
Les objets immuables sont donc sans aucun doute ma principale façon de penser la conception orientée objet, mais ils ne sont pas un dogme. Ils résolvent beaucoup de problèmes pour les clients d'objets, mais en créent aussi beaucoup, surtout pour les implémenteurs.
la source
Vous devez spécifier de 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 les langages de niveau supérieur, les objets immuables facilitent le raisonnement sur le comportement du code (en particulier le code multi-thread) car il n'y a pas "d'action effrayante à distance".
la source
Un objet mutable est simplement un objet qui peut être modifié après sa création / instanciation, par rapport à un objet immuable qui ne peut pas être modifié (voir la page Wikipédia sur le sujet). Un exemple de cela dans un langage de programmation est les listes et les tuples Pythons. Les listes peuvent être modifiées (par exemple, de nouveaux éléments peuvent être ajoutés après leur création), contrairement aux tuples.
Je ne pense pas vraiment qu'il y ait une réponse claire quant à laquelle est la meilleure pour toutes les situations. Ils ont tous les deux leur place.
la source
Si un type de classe est mutable, une variable de ce type de classe peut avoir un certain nombre de significations différentes. Par exemple, supposons qu'un objet
foo
possède un champint[] arr
et qu'il contienne une référence à unint[3]
contenant les nombres {5, 7, 9}. Même si le type de champ est connu, il peut représenter au moins quatre choses différentes:Une référence potentiellement partagée, dont tous les détenteurs se soucient uniquement qu'elle encapsule les valeurs 5, 7 et 9. Si vous
foo
souhaitezarr
encapsuler des valeurs différentes, elle doit la remplacer par un tableau différent contenant les valeurs souhaitées. Si l'on veut faire une copie defoo
, on peut donner à la copie une référencearr
ou un nouveau tableau contenant les valeurs {1,2,3}, selon ce qui est plus pratique.La seule référence, n'importe où dans l'univers, à un tableau qui encapsule les valeurs 5, 7 et 9. Ensemble de trois emplacements de stockage qui actuellement contiennent les valeurs 5, 7 et 9; s'il
foo
veut qu'il encapsule les valeurs 5, 8 et 9, il peut soit changer le deuxième élément de ce tableau, soit créer un nouveau tableau contenant les valeurs 5, 8 et 9 et abandonner l'ancien. Notez que si l'on veut faire une copie defoo
, il faut dans la copie remplacerarr
par une référence à un nouveau tableau afinfoo.arr
de rester la seule référence à ce tableau n'importe où dans l'univers.Une référence à un tableau qui appartient à un autre objet qui l'a exposé
foo
pour une raison quelconque (par exemple, il veut peut-êtrefoo
y stocker des données). Dans ce scénario,arr
n'encapsule pas le contenu du tableau, mais plutôt son identité . Comme le remplacementarr
par une référence à un nouveau tableau changerait totalement sa signification, une copie defoo
devrait contenir une référence au même tableau.Une référence à un tableau dont
foo
est le seul propriétaire, mais dont les références sont détenues par un autre objet pour une raison quelconque (par exemple, il veut avoir l'autre objet pour y stocker des données - le revers du cas précédent). Dans ce scénario,arr
encapsule à la fois l'identité du tableau et son contenu. Le remplacementarr
par une référence à un nouveau tableau changerait totalement sa signification, mais avoir unearr
référence à un clonefoo.arr
violerait l'hypothèse quifoo
est le seul propriétaire. Il n'y a donc aucun moyen de copierfoo
.En théorie,
int[]
devrait être un type simple et bien défini, mais il a quatre significations très différentes. En revanche, une référence à un objet immuable (par exempleString
) n'a généralement qu'une seule signification. Une grande partie du «pouvoir» des objets immuables provient de ce fait.la source
Les instances mutables sont passées par référence.
Les instances immuables sont passées par valeur.
Exemple abstrait. Supposons qu'il existe un fichier nommé txtfile sur mon disque dur. Maintenant, lorsque vous me demandez txtfile , je peux le retourner dans deux modes:
Dans le premier mode, le fichier txt renvoyé est un fichier modifiable, car lorsque vous effectuez des modifications dans le fichier de raccourci, vous effectuez également des modifications dans le fichier d'origine. L'avantage de ce mode est que chaque raccourci renvoyé nécessite moins de mémoire (sur la RAM ou sur le disque dur) et l'inconvénient est que tout le monde (pas seulement moi, propriétaire) a les autorisations pour modifier le contenu du fichier.
Dans le second mode, le fichier txt renvoyé est un fichier immuable, car toutes les modifications du fichier reçu ne font pas référence au fichier d'origine. L'avantage de ce mode est que seul moi (propriétaire) peut modifier le fichier d'origine et l'inconvénient est que chaque copie retournée nécessite de la mémoire (en RAM ou en disque dur).
la source
Si vous renvoyez les références d'un tableau ou d'une chaîne, le monde extérieur peut modifier le contenu de cet objet, et donc le rendre comme objet mutable (modifiable).
la source
Les moyens immuables ne peuvent pas être modifiés et modifiables signifie que vous pouvez changer.
Les objets sont différents des primitives en Java. Les primitives sont des types intégrés (booléen, int, etc.) et les objets (classes) sont des types créés par l'utilisateur.
Les primitives et les objets peuvent être mutables ou immuables lorsqu'ils sont définis comme des variables membres dans l'implémentation d'une classe.
Beaucoup de gens pensent que les primitives et les variables d'objet ayant un modificateur final devant elles sont immuables, cependant, ce n'est pas tout à fait vrai. Donc, final ne signifie presque pas immuable pour les variables. Voir l'exemple ici
http://www.siteconsortium.com/h/D0000F.php .
la source
Immutable object
- est un état d'objet dont l'état ne peut pas être modifié après sa création. L'objet est immuable lorsque tous ses champs sont immuablesFil sûr
Le principal avantage de l'objet immuable est qu'il s'agit naturellement d'un environnement concurrent. Le plus gros problème de la concurrence est de savoir
shared resource
qui peut être changé n'importe quel thread. Mais si un objet est immuable, c'estread-only
qui est une opération thread-safe. Toute modification d'un objet immuable d'origine renvoie une copiesans effets secondaires
En tant que développeur, vous êtes tout à fait sûr que l'état de l'objet immuable ne peut pas être modifié de n'importe quel endroit (volontairement ou non)
optimisation de la compilation
Améliorer les performances
Désavantage:
La copie d'un objet est une opération plus lourde que la modification d'un objet mutable, c'est pourquoi elle a une certaine empreinte de performances
Pour créer un
immutable
objet, vous devez utiliser:Niveau de langue. Chaque langue contient des outils pour vous y aider. Par exemple, Java a
final
etprimitives
, Swift alet
etstruct
[About] . Le langage définit un type de variable. Par exemple Java aprimitive
etreference
tapez, Swift avalue
etreference
tapez [About] . Pour les objets immuables, plus pratique estprimitives
etvalue
tapez qui fait une copie par défaut. Quant aureference
type, il est plus difficile (car vous pouvez en changer l'état de l'objet) mais possible. Par exemple, vous pouvez utiliser unclone
modèle au niveau du développeurNiveau développeur. En tant que développeur, vous ne devez pas fournir d'interface pour changer d'état
la source