Pourquoi avons-nous besoin d'une classe immuable?

je suis incapable d'obtenir ce que sont les scénarios où nous avons besoin d'une classe immuable.

Avez-vous déjà fait face à une telle exigence? ou pouvez-vous s'il vous plaît nous donner toute l'exemple réel où nous devrions utiliser ce modèle.

63
demandé sur Rakesh Juyal 2010-09-22 17:17:58

19 réponses

les autres réponses semblent se concentrer à expliquer pourquoi l'immuabilité est bonne. Il est très bon et je l'utilise chaque fois que possible. cependant, ce n'est pas votre question . Je vais prendre votre question point par point pour essayer de vous assurer que vous obtenez les réponses et les exemples dont vous avez besoin.

je suis incapable d'obtenir ce que sont les scénarios où nous avons besoin d'une classe immuable.

"Besoin" est un terme relatif ici. Les classes immuables sont un modèle de conception qui, comme tout paradigme/modèle/outil, est là pour rendre la construction du logiciel plus facile. De même, beaucoup de code a été écrit avant que le paradigme OO est venu le long, mais comptez-moi parmi les programmeurs que "besoin OO. Les classes immuables, comme OO , ne sont pas strictement nécessaire , mais je vais agir comme si j'ai besoin d'eux.

avez-vous déjà fait face à une telle exigence?

si vous ne regardez pas les objets dans le domaine de problème avec la bonne perspective, vous ne pouvez pas voir un exigence pour un objet immuable. Il pourrait être facile de penser qu'un domaine à problème ne ne nécessite aucune classe immuable si vous n'êtes pas familier quand les utiliser avantageusement.

j'utilise souvent des classes immuables où je pense à un objet donné dans mon domaine de problème comme une valeur ou instance fixe . Cette notion dépend parfois de la perspective ou du point de vue, mais idéalement, il sera facile de passer dans la bonne perspective pour identifier les bons objets candidats.

vous pouvez obtenir une meilleure idée de l'endroit où les objets immuables sont vraiment utile (si ce n'est pas strictement nécessaire) en vous assurant que vous lisez sur divers livres/articles en ligne pour développer un bon sens pour la façon de penser sur les classes immuables. Un bon article à , C'est la théorie et la pratique Java: muter ou ne pas muter?

je vais essayer de donner quelques exemples ci-dessous de comment on peut voir des objets dans différentes perspectives (mutable vs immuable) pour clarifier ce que je veux dire par perspective.

... pouvez vous s'il vous plaît nous donner toute l'exemple réel où nous devrions utiliser ce modèle.

puisque vous avez demandé de vrais exemples, je vais vous donner certains, mais commençons par quelques exemples classiques.

Classique Des Objets De Valeur

chaînes et entiers et sont souvent considérés comme des valeurs. Il n'est donc pas surprenant de constater que les classes String et Integer wrapper (ainsi que les autres classes wrapper) sont immuables en Java. Une couleur est généralement considéré comme une valeur, donc l'immuable classe de Couleur.

contre-exemple

En revanche, une voiture n'est pas généralement considéré comme un objet de valeur. Modéliser une voiture signifie généralement une création d'une classe qui a l'état changeant (odomètre, vitesse, niveau de carburant, etc). Cependant, il ya certains domaines où il voiture peut être un objet de valeur. Par exemple, une voiture (ou plus précisément un modèle de voiture) pourrait être considérée comme un objet de valeur dans une application pour rechercher l'huile à moteur appropriée pour un véhicule donné.

Cartes À Jouer

vous avez déjà écrit un programme de cartes à jouer? Je l'ai fait. J'aurais pu représenter une carte à jouer comme un objet mutable avec un costume mutable et un rang. Une main de draw-poker pourrait être 5 instances fixes où remplacer la 5ème carte dans ma main signifierait la mutation de la 5ème instance de jeu de carte dans une nouvelle carte en changeant son costume et le rang ivars.

Cependant, j'ai tendance à penser d'une carte à jouer comme un objet immuable, qui est fixe, immuable, couleur et rang une fois créé. Ma main draw poker serait de 5 instances et remplacer une carte dans ma main impliquerait de rejeter une de ces instances et d'ajouter une nouvelle instance aléatoire à ma main.

Projection De La Carte

un dernier exemple est quand j'ai travaillé sur un code de carte où la carte pourrait s'afficher dans diverses projections . Le code original avait la carte utiliser une instance de projection fixe, mais mutable (comme la carte à jouer mutable ci-dessus). Changer la projection de la carte signifiait muter les ivars de l'instance de projection de la carte (type de projection, point central, zoom, etc.).

cependant, j'ai senti que le design était plus simple si je pensais à une projection comme une valeur immuable ou une instance fixe. Changer la projection de la carte signifiait avoir la référence de la carte une instance de projection différente plutôt que de muter l'instance de projection fixe de la carte. Cela a également simplifié la capture de named projections telles que MERCATOR_WORLD_VIEW .

65
répondu Bert F 2013-05-06 13:27:18

classes immuables sont en général beaucoup plus simple à concevoir, mettre en œuvre et utiliser correctement . Un exemple est String: l'implémentation de java.lang.String est significativement plus simple que celle de std::string en C++, principalement en raison de son immuabilité.

un domaine particulier où l'immutabilité fait une différence particulièrement grande est la concurrence: les objets immuables peuvent être partagés en toute sécurité entre plusieurs threads , alors que mutable les objets doivent être rendus thread-safe via une conception et une mise en œuvre soignées - Généralement, cela est loin d'être une tâche triviale.

mise à Jour: Effective Java 2nd Edition aborde cette question en détail - voir Article 15: Minimiser la mutabilité .

voir aussi ces articles connexes:

39
répondu Péter Török 2017-05-23 10:31:09

Java efficace par Joshua Bloch décrit plusieurs raisons d'écrire des classes immuables:

  • simplicité-chaque classe est dans un seul État
  • Thread-Safe - parce que l'état ne peut pas être changé, aucune synchronisation n'est nécessaire
  • écrire dans un style immuable peut conduire à un code plus robuste. Imaginez si les chaînes de caractères n'étaient pas immuables; toute méthode getter qui renvoie une chaîne de caractères nécessiterait l'implémentation de créez une copie défensive avant que la chaîne de caractères ne soit retournée - sinon un client peut accidentellement ou malicieusement briser cet état de l'objet.

en général, il est recommandé de rendre un objet immuable à moins qu'il n'en résulte de graves problèmes de performance. Dans de telles circonstances, des objets de construction mutables peuvent être utilisés pour construire des objets immuables, par exemple StringBuilder

36
répondu Tarski 2014-07-18 18:08:05

Hashmaps en est un exemple classique. Il est impératif que la clé d'une carte soit immuable. Si la clé n'est pas immuable, et que vous changez une valeur sur la clé de telle sorte que hashCode() aboutirait à une nouvelle valeur, la carte est maintenant cassée (une clé est maintenant au mauvais endroit dans la table de hachage.).

11
répondu Kirk Woll 2010-09-22 13:21:15

Java est pratiquement une et toutes les références. Parfois, une instance est référencée plusieurs fois. Si vous changez une telle instance, elle sera reflétée dans toutes ses références. Parfois, vous ne voulez tout simplement pas avoir cela pour améliorer la robustesse et la sécurité thread. Alors une classe immuable est utile pour que l'on soit forcé de créer une instance nouvelle et de la réassigner à la référence actuelle. De cette façon, l'instance originale des autres références reste intacte.

imaginez à quoi ressemblerait Java si String était mutable.

7
répondu BalusC 2010-09-22 13:28:48

we don't need classes immuables, en soi, mais ils peuvent certainement rendre certaines tâches de programmation plus facile, surtout lorsque plusieurs threads sont impliqués. Vous n'avez pas à effectuer de verrouillage pour accéder à un objet immuable, et tout fait que vous avez déjà établi au sujet d'un tel objet continuera à être vrai dans le futur.

6
répondu Damien_The_Unbeliever 2010-09-22 13:22:15

il y a plusieurs raisons pour l'immuabilité:

  • sécurité du Thread: les objets immuables ne peuvent pas être changés et leur état interne ne peut pas changer, il n'est donc pas nécessaire de les synchroniser.
  • il garantit également que tout ce que j'envoie (via un réseau) doit être dans le même état que précédemment envoyé. Cela signifie que personne n' (espion) peut venir et ajouter des données aléatoires dans mon immuable ensemble.
  • c'est aussi plus simple développer. Vous garantissez qu'aucune sous-classes existent si un objet est immuable. Par exemple: une classe String .

ainsi, si vous voulez envoyer des données à travers un service réseau, et vous voulez un sens de garantie que vous aurez votre résultat exactement le même que ce que vous avez envoyé, définissez-le comme immuable.

5
répondu Buhake Sindi 2010-09-22 13:44:22

prenons un cas extrême: les constantes entières. Si j'écris une déclaration comme "x=x+1", je veux être sûr à 100% que le nombre "1" ne deviendra pas 2, Peu importe ce qui se passe ailleurs dans le programme.

maintenant OK, les constantes entières ne sont pas une classe, mais le concept est le même. Supposons que j'écrive:

String customerId=getCustomerId();
String customerName=getCustomerName(customerId);
String customerBalance=getCustomerBalance(customerid);

semble assez simple. Mais si les cordes n'étaient pas immuables, alors je devrais envisager la possibilité que getCustomerName pourrait changer customerId, de sorte que lorsque j'appelle getCustomerBalance, j'obtiens le solde pour un client différent. Maintenant, vous pourriez dire, " pourquoi dans le monde quelqu'un écrivant une fonction getCustomerName le ferait changer l'id? Cela n'aurait aucun sens."Mais c'est exactement là que tu pourrais avoir des ennuis. La personne écrivant le code ci-dessus pourrait considérer comme évident que les fonctions ne changeraient pas le paramètre. Puis quelqu'un arrive qui doit modifier une autre utilisation de ce fonction pour gérer le cas où un client a plusieurs comptes sous le même nom. Et il dit, " Oh, voici cette pratique Fonction nom de client getCustomer qui cherche déjà le nom. Je vais juste faire que changer automatiquement l'id sur le prochain compte avec le même nom, et le mettre dans une boucle ..."Et votre programme commence mystérieusement à ne pas fonctionner. Ce serait un mauvais style de codage? Probablement. Mais c'est précisément un problème dans les cas où l'effet secondaire n'est PAS évident.

Immutabilité signifie simplement qu'une certaine classe d'objets sont des constantes, et nous pouvons les traiter comme des constantes.

(bien sûr, l'utilisateur peut assigner un" objet constant " différent à une variable. Quelqu'un peut écrire String s = " hello"; et puis, plus tard écrire s="au revoir"; À moins de rendre la variable finale, Je ne peux pas être sûr qu'elle ne soit pas changée dans mon propre bloc de code. Tout comme les constantes entières m'assurer que "1" est toujours le même nombre, mais pas que "x=1 "ne sera jamais modifié en écrivant"x=2". Mais je peux être confiant que si j'ai un handle vers un objet immuable, qui ne fonctionne pas je le passe à peut changer sur moi, ou que si je fais deux copies, qu'un changement de la variable contenant une copie ne va pas changer les autres. Etc.

5
répondu Jay 2010-09-22 14:04:42

je vais l'attaquer d'un autre point de vue. Je trouve que les objets immuables me facilitent la vie en lisant du code.

si j'ai un objet mutable, Je ne suis jamais sûr de sa valeur s'il est utilisé hors de ma portée immédiate. Disons que je crée MyMutableObject dans les variables locales d'une méthode, le remplis avec des valeurs, puis le passe à cinq autres méthodes. N'importe laquelle de ces méthodes peut changer l'état de mon objet, donc une des deux choses doit se produire:

  1. je dois suivre les corps de cinq méthodes supplémentaires tout en pensant à la logique de mon code.
  2. je dois faire cinq copies défensives gaspillées de mon objet pour m'assurer que les bonnes valeurs sont passées à chaque méthode.

le premier rend difficile le raisonnement sur mon code. Le second fait que mon code est nul en performance -- j'imite un objet immuable avec une sémantique de copie-sur-écriture bref, mais en le faisant tout le temps, que les méthodes appelées modifient ou non l'état de mon objet.

Si j'utilise plutôt MyImmutableObject , je peux être assuré que ce que j'ai mis est ce que les valeurs pour la vie de ma méthode. Il n'y a pas d ' "action effrayante à distance" qui puisse la changer et il n'est pas nécessaire que je fasse des copies défensives de mon objet avant d'invoquer les cinq autres méthodes. Si les autres méthodes veulent changer les choses à leurs fins ils doivent faire la copie – mais ils ne le font que s'ils doivent vraiment faire une copie (par opposition à ce que je le fais avant chaque appel de méthode externe). Je m'épargne les ressources mentales de garder la trace des méthodes qui ne peuvent même pas être dans mon fichier source actuel, et j'épargne au système la charge de faire sans cesse des copies défensives inutiles juste au cas où.

(si je vais en dehors du monde Java et dans, disons, le monde C++, d'autres, je peux être encore plus rusé. Je peux faire apparaître les objets comme s'ils étaient muables, mais dans les coulisses, les faire cloner de façon transparente sur n'importe quel changement d'état-c'est copier-écrire-sans que personne ne soit plus avisé.)

5
répondu JUST MY correct OPINION 2010-09-22 15:07:42

L'Utilisation du mot-clé final ne rend pas nécessairement quelque chose immuable:

public class Scratchpad {
    public static void main(String[] args) throws Exception {
        SomeData sd = new SomeData("foo");
        System.out.println(sd.data); //prints "foo"
        voodoo(sd, "data", "bar");
        System.out.println(sd.data); //prints "bar"
    }

    private static void voodoo(Object obj, String fieldName, Object value) throws Exception {
        Field f = SomeData.class.getDeclaredField("data");
        f.setAccessible(true);
        Field modifiers = Field.class.getDeclaredField("modifiers");
        modifiers.setAccessible(true);
        modifiers.setInt(f, f.getModifiers() & ~Modifier.FINAL);
        f.set(obj, "bar");
    }
}

class SomeData {
    final String data;
    SomeData(String data) {
        this.data = data;
    }
}

juste un exemple pour démontrer que le mot-clé" final " est là pour empêcher l'erreur du programmeur, et pas beaucoup plus. Alors que réassigner une valeur sans mot-clé final peut facilement se produire par accident, aller à cette longueur pour changer une valeur devrait être fait intentionnellement. Il est là pour la documentation et pour prévenir les erreurs de programmation.

1
répondu Mark Peters 2010-09-22 15:12:49

des structures de données immuables peuvent également aider lors du codage des algorithmes récursifs. Par exemple, dites que vous essayez de résoudre un problème 3sat . Une façon est de faire ce qui suit:

  • Choisissez une variable non assignée.
  • lui donne la valeur de TRUE. Simplifiez l'instance en retirant les clauses qui sont maintenant satisfaites, et recommencez à résoudre l'instance plus simple.
  • si la récursion sur le vrai cas échoué, puis attribuer cette variable FALSE à la place. Simplifiez cette nouvelle instance, et recommencez à la résoudre.

si vous avez une structure mutable pour représenter le problème, alors quand vous simplifiez l'instance dans la branche vraie, vous devrez soit:

  • Gardez une trace de tous les changements que vous faites, et annulez-les tous une fois que vous réalisez que le problème ne peut pas être résolu. Cela a de grands frais généraux parce que votre récursion peut aller assez profond, et il est difficile de code.
  • fait une copie de l'instance, puis modifie la copie. Cela sera lent car si votre récursion est profonde de quelques dizaines de niveaux, vous devrez faire de nombreuses copies de l'instance.

cependant si vous le codez d'une manière intelligente, vous pouvez avoir une structure immuable, où n'importe quelle opération renvoie une version mise à jour (mais toujours immuable) du problème (similaire à String.replace - il ne remplace pas la chaîne, vous donne juste un nouveau). La manière naïve de mettre en œuvre ceci est d'avoir la structure "immuable" juste copier et faire une nouvelle sur n'importe quelle modification, la réduisant à la deuxième solution quand avoir une mutable, avec tout cela au-dessus de la tête, mais vous pouvez le faire d'une manière plus efficace.

1
répondu Claudiu 2010-09-22 15:27:12

L'une des raisons de la" nécessité "de classes immuables est la combinaison de tout passer par référence et n'ayant aucun support pour les vues en lecture seule d'un objet (i.e. c++'s const ).

Considérons le cas simple d'une classe d'avoir du soutien pour le modèle observateur:

class Person {
    public string getName() { ... }
    public void registerForNameChange(NameChangedObserver o) { ... }
}

si string n'étaient pas immuables, il serait impossible pour la classe Person de mettre en œuvre registerForNameChange() correctement, parce que quelqu'un pourrait écrire ce qui suit, modifiant effectivement le nom de la personne sans déclencher aucune notification.

void foo(Person p) {
    p.getName().prepend("Mr. ");
}

En C++, getName() retour const std::string& a pour effet de retour par référence et empêcher l'accès à des mutateurs, sens immuable classes ne sont pas nécessaires dans ce contexte.

1
répondu André Caron 2010-09-22 15:36:08

Ils nous donnent aussi une garantie. La garantie de l'immutabilité signifie que nous pouvons les développer et créer de nouveaux modèles d'efficacité qui ne sont pas possibles autrement.

http://en.wikipedia.org/wiki/Singleton_pattern

1
répondu Ryan Hayes 2010-09-22 15:38:36

une caractéristique des classes immuables qui n'a pas encore été appelée: stocker une référence à un objet de classe profondément immuable est un moyen efficace de stocker tout l'état qu'il contient. Supposons que j'ai un objet mutable qui utilise un objet profondément immuable pour contenir 50K d'information d'état. Supposons, en outre, que je souhaite à 25 reprises faire une "copie" de mon objet original (mutable) (par exemple pour un tampon" undo"); l'État pourrait changer entre les opérations de copie, mais d'habitude, non. Faire une "copie" de l'objet mutable exigerait simplement de copier une référence à son état immuable, donc 20 copies équivaudraient tout simplement à 20 références. En revanche, si L'État était détenu dans des objets mutables d'une valeur de 50K, chacune des 25 opérations de copie devrait produire sa propre copie de données d'une valeur de 50K; la détention des 25 copies nécessiterait la détention de plus d'une valeur meg de données pour la plupart dupliquées. Même si la première opération de copie produirait une copie des données qui ne jamais changer, et les 24 autres opérations pourraient en théorie simplement renvoyer à cela, dans la plupart des implémentations il n'y aurait aucun moyen pour le second objet demandant une copie de l'information de savoir qu'une copie immuable existe déjà(*).

( * ) un modèle qui peut parfois être utile est pour les objets mutables d'avoir deux champs pour tenir leur état--un dans la forme mutable et un dans la forme immuable. Les objets peuvent être copiés comme mutables ou immuables, et commenceraient la vie avec l'un ou l'autre ensemble de référence. Dès que l'objet souhaite changer d'état, il copie l'immuable référence à la mutable (s'il n'a pas déjà été fait) et invalide l'immuable. Lorsque l'objet est copié comme immuable, si son immuable de référence n'est pas défini, immuable copie sera créé et l'immuable référence souligné que. Cette approche exigera un peu plus d'opérations de copie qu'une "copie complète en écriture" (par exemple, demander de copier un objet qui a muté puisque la dernière copie nécessiterait une opération de copie, même si l'objet original n'est plus jamais muté) mais il évite les complexités de threading que FFCOW entraînerait.

1
répondu supercat 2012-05-02 15:51:35

les objets immuables sont des instances dont les États ne changent pas une fois initialisés. L'utilisation de tels objets est spécifique aux besoins.

classe immuable est bon pour la mise en cache et il est sans fil.

1
répondu Shreya Agarwal 2018-06-20 05:03:32

de Java Effective; Immuable classe est simplement une classe dont les instances ne peuvent pas être modifiés. Tout l'information contenue dans chaque instance est fournie quand elle est créée et est fixe pour la durée de vie de l'objet. Les bibliothèques de plate-forme Java contiennent classes immuables, y compris String, les classes primitives en boite, et BigInte- ger et BigDecimal. Il y a plusieurs bonnes raisons à cela: les classes immuables sont plus faciles à concevoir, à mettre en œuvre et à utiliser que les classes mutables. Ils sont moins sujettes à l'erreur et sont plus sûrs.

0
répondu tarikfasun 2015-07-27 14:26:55

par immutabilité vous pouvez être sûr du comportement à ne pas changer, avec cela vous obtenez l'avantage supplémentaire d'effectuer des opérations supplémentaires:

  • vous pouvez utiliser plusieurs core/processing ( traitement simultané ) avec at facilité(car la séquence n'aura plus d'importance.)

  • Peut faire "l'151950920" mise en cache pour une opération coûteuse(que vous êtes sûr de le même

    résultat.)

  • Peut faire "l'151950920" débogage à l'aise(comme l'histoire de la course ne sera pas de la "préoccupation 1519130920"
    anymore)

0
répondu Arun Pratap Singh 2017-05-08 17:41:25

pourquoi classe immuable?

une fois qu'un objet est instancié, il ne peut pas être modifié dans sa vie. Ce qui le rend également Fil sûr.

exemples:

évidemment chaîne, entier et BigDecimal etc. Une fois que ces valeurs sont créées ne peut pas être changé dans la vie.

: Une fois que L'objet de connexion à la base de données est créé avec ses valeurs de configuration vous pourriez ne pas avoir besoin de changer son état où vous pouvez utiliser une classe immuable

0
répondu bharanitharan 2018-01-04 06:56:01

My 2 cents pour les futurs visiteurs:



2 scénarios où les objets immuables sont de bons choix sont:

en filetage multiple

les problèmes de concurrence dans un environnement multi-threadé peuvent très bien être résolus par la synchronisation mais la synchronisation est une affaire coûteuse( ne creuserait pas ici sur "Pourquoi"), donc si vous utilisez des objets immuables alors il y a pas de synchronisation pour résoudre le problème de concurrence parce que l'état des objets immuables ne peut pas être changé, et si l'état ne peut pas être changé, alors tous les threads peuvent accéder sans problème à l'objet. ainsi, les objets immuables font un grand choix pour les objets partagés dans un environnement multi-threadé.



Comme la clé de hachage en fonction des collections

une des choses les plus importantes à noter pendant le travail avec collection à base de hash est que la clé doit être telle que son hashCode() doit toujours retourner la même valeur pour la durée de vie de l'objet, parce que si cette valeur est modifiée, alors l'ancienne entrée faite dans la collection à base de hash en utilisant cet objet ne peut pas être récupéré, donc il causerait fuite de mémoire. puisque l'état des objets immuables ne peut pas être changé, ils font un grand choix comme clé dans la collection basée sur le hash. donc, si vous utilisez un objet immuable comme clé de hachage basé sur la collecte alors vous pouvez être sûr qu'il n'y aura pas de fuite de mémoire à cause de cela (bien sûr, il peut toujours y avoir une fuite de mémoire quand l'objet utilisé comme clé n'est pas référencé ailleurs, mais ce n'est pas le point ici).

0
répondu hagrawal 2018-08-21 20:45:31