Je souhaite alerter le développeur lorsqu'il tente de muter un objet immuable. L'objet immuable est en réalité une extension d'un objet mutable et remplace les setters sur ledit objet pour la rendre immuable.
Classe de base mutable: Version immuable: mon cas d'utilisation est la suivante: p> if (position == Vector3.Zero)
position = new Vector3(x, y, z);
4 Réponses :
Lancer une exception est généralement la voie à suivre et vous devriez utiliser non pris en chargeOrexceptionException code>
.
L'API Java elle-même recommande cela dans le Cadre de collections : P>
Les méthodes "destructives" contenues dans cette interface, c'est-à-dire les méthodes qui modifient la collection sur laquelle elles fonctionnent sont spécifiées pour lancer une introduction non pratiquéeOrexception si cette collection ne prend pas en charge l'opération. P> BlockQuote>
une alternative forte> Si vous créez la hiérarchie de la classe complète consiste à créer une super classe
vecteur code> qui n'est pas modifiable et n'a pas de méthodes de modification comme
Définir () code> et deux sous-classes
immutacultvector code> (qui garantit une immuabilité) et
mutabiltaturvector code> (qui est modifiable). Ce serait mieux parce que vous obtenez la sécurité du temps complets (vous ne pouvez même pas essayer de modifier un
immutacultvector code>), mais en fonction de la situation peut être trop conçu (et vous pourriez vous retrouver avec de nombreuses classes ). P>
Cette approche était par exemple choisi pour le Collections Scala , ils existent tous dans trois variations. p>
Dans tous les cas où vous souhaitez modifier le vecteur, vous utilisez le type
mutatablevector code>. Dans tous les cas où vous ne vous souciez pas de modifier et de vouloir simplement en lire, vous utilisez simplement
vecteur code>. Dans tous les cas où vous souhaitez garantir une immuabilité (par exemple, une instance code> code> est passée dans un constructeur et que vous souhaitez vous assurer que personne ne la modifiera plus tard), vous utilisez
immutatingvector code> ( qui fournirait généralement une méthode de copie, vous venez d'appeler
immutacultvector.copyof (vecteur) code>). Down-Casting de
Vecteur code> ne doit jamais être nécessaire, spécifiez le sous-type correct dont vous avez besoin en tant que type. Tout le point de cette solution (qui a besoin de plus de code) consiste à être sûr de type sûr et de chèques de compilation, de sorte que la coulée de descente détruisit l'avantage. Il existe des exceptions, cependant, par exemple le
immutitablevector.copyof () code> la méthode serait, comme une optimisation, ressemblait généralement à ceci: p>
xxx pré> ceci est toujours en sécurité et vous donne un autre bénéfice des types immuables, à savoir l'évitement de la copie inutile. p>
le Bibliothèque de Guava possède une grande collection de Collection immuable < / a> Mises en œuvre qui suivent ce modèle (bien qu'ils étendent toujours les interfaces de collecte Java standard mutable et ne fournissent donc aucune sécurité du temps de compilation). Vous devriez lire la description d'eux pour en savoir plus sur les types immuables. P>
La troisième alternative forte> serait de disposer d'une classe de vecteur immuable et de classes mutables du tout. Les classes très souvent mutables utilisées pour des raisons de performance sont une optimisation prématurée, car Java Est très bon dans la manipulation de nombreux objets temporaires de petite taille (en raison d'un collecteur de déchets générationnel, une allocation d'objet est extrêmement bon marché et le nettoyage d'objets peut même être sans frais dans le meilleur cas). Bien sûr, ce n'est pas une solution pour des objets très gros tels que des listes, mais pour un vecteur tridimensionnel, c'est sûrement une option (et probablement la meilleure combinaison, car sa facilité, sa sécurité et sa nécessité de moins de code que les autres). Je ne connais aucun exemple dans l'API de Java de cette alternative, car de retour dans les jours où la plupart des parties de l'API ont été créées, le VM n'était pas si optimisé et si trop d'objets étaient peut-être un problème de performance. Mais cela ne devrait pas vous empêcher de le faire aujourd'hui. P> p>
La super classe aurait-elle toujours une méthode () code> sur elle? Sans la méthode
Set () Code> sur la base ou une interface, je vais devoir jeter jusqu'à
Mutablevector Code> afin d'accéder au Setter, ce qui signifie également vérifier si
Position Code> est une instance de
mutabiltaturvector code> en premier.
Dans ce cas, cependant, je veux muter l'instance uniquement s'il n'est pas défini sur une instance immuable en premier. Si c'est une instance immuable, je souhaite créer une nouvelle instance mutable et affecter cela à position code>. Ainsi, je devrais toujours me lancer vers
Mutabiltaturvector Code> à partir de ce moment-là afin de
SET CODE> Le vecteur.
Problèmes de performance de la barrage, vous devriez s'efforcer de simplement avoir une classe immuable. Cela aura l'avantage supplémentaire d'éviter une hiérarchie de base / immuable / mutable chaque fois que vous entrez dans cette situation.
Dans ce cas, vous pouvez (et devez-vous avoir besoin), bien que je n'aime vraiment pas ce genre de conception.
Le problème de les rendre tous immuables est que mes mains sont liées à la JPA ne permettant pas la sérialisation des champs finaux (qui me fait bogler, mais quoi que ce soit).
Je ne suis pas sûr de savoir si cela vous aide, mais il y a une question de JPA et des types immuables: Stackoverflow.com/questions/7222366/...
Je voulais vous remercier pour toutes les informations et la recherche à ce sujet. J'ai décidé d'aller avec un peu de ce que vous avez suggéré avec une suggestion de Thiket ci-dessus. Je vais utiliser une interface pour vector3 code>, mais place
SET () code> dessus. Il retournera une instance
vector3 code>. Cette instance sera
ceci code> sur
mutatablevector3 code> et
neuf mutablesvector3 (x, y, z) code> sur
immutatevector3 code>. Cela aidera à favoriser le modèle de poids volé que je souhaite recevoir. Je ne peux pas décider quelle réponse à accepter, car, depuis que vous avez tous deux contribué de manière égale à ma solution à mon estimation.
Je vous ai donné l'acceptation parce que votre réponse est la plus verbeuse et couvre de nombreuses approches.
Vous devez lancer une erreur de compilateur si vous essayez de muter une classe immuable. p>
Les classes immuables ne doivent pas s'étendre mutables. P>
Dites-vous: extraire une interface de la classe mutable et avoir la classe immuable implémente cette interface à la place?
Je n'étais pas trop sûr d'étendre une classe mutable et d'essayer de le rendre immuable. Avez-vous d'autres suggestions sur la manière dont je pourrais gérer les situations ci-dessus?
Je préférerais que Java prit en charge les méthodes const code> à la place, ce qui contribuerait grandement à résoudre ce non-sens, mais il est trop tard pour cela. :-)
Compte tenu de votre situation, je pense que vous devriez jeter un non pris en chargeOrexception code>. Voici pourquoi:
package com.sandbox;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Sandbox {
public static void main(String[] args) throws IOException {
List<Object> objects = Collections.unmodifiableList(new ArrayList<Object>());
objects.add(new Object());
}
}
J'ai envisagé la suggestion de Sotiriosdelimanolis. Je ne serais-je pas obligé de jeter jusqu'à Mutablevector3 Code> afin de la muter? Cela nécessiterait également un contrôle supplémentaire:
si (instance de position de mutabiltaturvector3) code> je crois.
@crush vous pourrait i>. Cela dépend de votre code hérité. Si vous avez du code qui dépend de la mise en œuvre des méthodes mutables du vecteur, vous auriez à votre disposition. Vous pourriez être en mesure de refactoriser la méthode Set CODE> CODE> de Vector mutable afin qu'il renvoie son propre type. Ensuite, tous les codes hérités utilisent le résultat du setter. Ensuite, votre code hérité dépendra de votre nouvelle interface plutôt que de l'ancienne mise en œuvre.
Quelque chose comme mutabiltaturvector3 code>,
Public Vector3 Set (x, y, z) {/*...*/ retourne ceci; } code> et sur
immutacultvector3 code>,
Publique vector3 Set (x, y, z) {/*...*/ retour Nouveau vecteur3 (x, y, z); code>?
@crush Oui. Si vous faites tout dans le code hérité qui appelle mutatablevector3.set code> Toujours faire ceci:
x.mymutablevector = x.mymutablevector.set (x, y, z); code> alors vous devriez Soyez capable de remplacer toutes les implémentations avec votre
immutacultvector3 code> et supprimez votre
mutabiltaturvector3 code>. Malheureusement, le compilateur ne vous aidera pas si vous oubliez de dire
x.mymutablevector = code>
J'aime vraiment votre suggestion de retourner une instance à partir de la méthode code> (code>. Cela simplifie mon code même et facilite le modèle de poids volé! Lorsque quelqu'un tente de figurer sur le cas spécial immuable, ils obtiendront un vecteur mutable3 avec les valeurs qu'ils définies peuvent ensuite être utilisées à partir de ce moment. Ceci, avec une interface / des objets mutables / immuables, est là que j'ai décidé de prendre! Je rencontre des difficultés à décider de la réponse à accepter, cependant, car vous avez tous deux aidé de manière égale à ma solution.
@crush ce n'est pas l'itinéraire que je suggérais, mais si c'est ce qui fonctionne le mieux pour vous, cela pourrait être viable. Je pense que définir code> sur
immutacultvector code> doit renvoyer un autre
immutatevector code>.
Dans la plupart des cas, peut-être, mais la façon dont je l'utilise, il est préférable qu'il retourne un vecteur mutable. Je serai sûr de le documenter de manière appropriée. Merci.
Les classes immuables ne doivent pas dériver de classes mutables concrètes, ni inversement. Au lieu de cela, vous devez avoir un L'aspect le plus difficile est de décider s'il est préférable d'avoir la classe de base inclure une méthode permettant de vérifier si elle est mutable avec une méthode "définie" qui jettera si elle ne l'est pas, ou si elle omet simplement omettre la méthode "SET" . Je préférerais omettre la méthode "Set", sauf si le type inclut des fonctionnalités pour faciliter un motif de copie-écriture. P>
Un tel motif peut être facilité par le fait que la classe de base inclut des méthodes abstraites lishablefoo code> Classe abstraite avec concrets
Mutablefoo code> et
immutatefoo code> dérivés. De cette façon, une méthode qui veut un objet, elle peut muté peut exiger
mutablablefoo code>, une méthode qui souhaite un objet dont l'état actuel peut être persisté simplement en persistant une référence à l'objet peut exiger
immutatefoo code> et une méthode qui ne veut pas changer d'état d'objet et ne se souciera pas de ce que l'état après son retour peut accepter librement
lisiblefoo code> sans avoir à craindre d'être mutable ou immuable. p>
asimmutable code>,
asmutable code>, avec du béton
asNewMutable code>. Procédé qui reçoit un
lisiblefoo code> nommé
george code> et veut capturer son état actuel peut stocker sur un champ
georgefield code>
george.asimmutable () code> ou
george.asNewMutable () code> selon que cela pense qu'il souhaite la modifier. S'il doit le modifier, il peut définir
georgefield = georgefield.asmutable () code>. Si cela doit le partager, il peut renvoyer
georgefield.asimmauttable () code>; S'il s'attend à la partager plusieurs fois avant de la modifier à nouveau, il peut définir
georgefield = georgefield.asimmauttable () code>. Si de nombreux objets doivent partager les États
... FOO CODE> S, et la plupart d'entre eux n'ont pas besoin de les modifier du tout, mais ont besoin de les modifier beaucoup, une telle approche peut s'entraîner plus efficacement que d'utiliser uniquement des objets mutables ou immuables. P>
Considérez mon exemple ci-dessus. J'ai MyObject code> avec le membre
position code> dessus.
Position Code> est un
Vector3 code>. Disons que
vector3 code> est une classe de base / interface, et j'ai
mutabiltavector3 code> et
immutacultvector3 code> qui en dérive.
Position Code> est initialement défini sur une instance de
immutacultaturvector3 code>. Il reste un
immutacultvector3 code> jusqu'à ce que
la position code> doit changer. À ce stade, un nouveau
mutabiltaturvector3 code> sera créé à la position modifiée et utilisé à partir de l'avant vers l'avant. Toutefois, si
SET () code> est omis de la base / de l'interface, je voulais
SET () CODE> J'aurais besoin de vérifier l'immuabilité.
@crush: si définir les méthodes code> a été omis de l'interface de base, il serait probable que la santé mentale doit probablement inclure un
Assameutable () code> [retour auto i> exception mutable ou lancer]; Si on voulait appeler
setxx code> et
setyy code> sur
georgefield code>, il aurait besoin de
georgefield = georgefield.asmutable (); Georgefield.assamemutable.setxx (); Georgefield.assamemutable.Setyyy (); code>. Si l'on utilise
asmutable code> plutôt que
assamempeutable code> et omis le premier
asmutable code> en pensant à tort qu'il était déjà arrivé, les tentatives de définition de XX et YY seraient silencieusement échouer.
J'irais avec
UnsppoertedoperationException code>. Le
non modifiable * code> décorateurs de
Collection code> est un bon précédent.
@crush résolvez-vous une question de performance connue i> en faisant de vecteur3d mutable? Sinon, le rendre immuable. Laissez les gens construire une nouvelle instance quand ils veulent de nouvelles valeurs. Problème de performance connue = Vous avez effectué des tests / analyses de performance, et c'est le goulot d'étranglement.
@ERICSTEIN Les valeurs du vecteur3 changeront chaque seconde ou plus fréquemment pour des centaines de milliers d'objets dans mon champ d'application. Je suis sous la présomption, éventuellement fausse, qui crée un nouvel objet Vector3 à chaque fois que je dois modifier la position d'un objet susceptible de provoquer des problèmes avec des pauses de GC et / ou d'être plus lente que de définir simplement la nouvelle position sur un objet existant.
@crush Je ne peux pas promettre que ce ne sera pas un problème, mais Java est plutôt bon à traiter d'objets de courte durée (je blâme la dimension). Vous voudrez peut-être l'essayer et voir s'il souffle d'abord de votre code.
@Ericstein en fait, je viens de rappeler ce fait, qu'une autre limitation ici avec la fabrication de vecteur3 immuable est que la JPA n'autorise pas les objets immutables à être sérialisé et nous utilisons JPA pour notre couche d'abstraction DB / sérialisation.
@crush c'est la fin de cette fête. Tout ce hubaloo est pour une instance, non? Le vecteur zéro? Jetez non-prise en chargeOperationException, comme tout le monde a dit (à juste titre).
J'ai une poignée d'une même poignée d'instances statiques, sharables et volantes, comme cela, mais essentiellement oui.