J'ai un algorithme qui crée une collection d'objets. Ces objets sont mutables lors de la création, car ils commencent avec très peu, mais ils sont ensuite remplis de données à différents endroits de l'algorithme.
Une fois l'algorithme terminé, les objets ne doivent jamais être modifiés, mais ils sont consommés par d'autres parties du logiciel.
Dans ces scénarios, est-il considéré comme une bonne pratique d'avoir deux versions de la classe, comme décrit ci-dessous?
- Le mutable est créé par l'algorithme, puis
- À la fin de l'algorithme, les données sont copiées dans des objets immuables qui sont retournés.
Réponses:
Vous pouvez peut-être utiliser le modèle de générateur . Il utilise un objet «constructeur» distinct dans le but de collecter les données nécessaires, et lorsque toutes les données sont collectées, il crée l'objet réel. L'objet créé peut être immuable.
la source
Un moyen simple d'y parvenir serait d'avoir une interface qui permet de lire les propriétés et d'appeler uniquement des méthodes en lecture seule et une classe qui implémente cette interface qui vous permet également d'écrire cette classe.
Votre méthode qui le crée, traite le premier, puis renvoie le second fournissant uniquement une interface en lecture seule avec laquelle interagir. Cela ne nécessiterait aucune copie et vous permet d'affiner facilement les comportements que vous souhaitez mettre à la disposition de l'appelant plutôt que du créateur.
Prenez cet exemple:
Le seul inconvénient de cette approche est que l'on peut simplement la convertir en classe d'implémentation. S'il s'agissait d'une question de sécurité, alors simplement utiliser cette approche est insuffisant. Une solution de contournement à cela est que vous pouvez créer une classe de façade pour encapsuler la classe mutable, qui présente simplement une interface avec laquelle l'appelant travaille et ne peut pas avoir accès à l'objet interne.
De cette façon, même le casting ne vous aidera pas. Les deux peuvent dériver de la même interface en lecture seule, mais la conversion de l'objet renvoyé ne vous donnera que la classe Facade, qui est immuable car elle ne change pas l'état sous-jacent de la classe mutable enveloppée.
Il convient de mentionner que cela ne suit pas la tendance typique dans laquelle un objet immuable est construit une fois pour toutes à travers son constructeur. Naturellement, vous devrez peut-être traiter de nombreux paramètres, mais vous devez vous demander si tous ces paramètres doivent être définis à l'avance ou si certains peuvent être introduits plus tard. Dans ce cas, un constructeur simple avec uniquement les paramètres requis doit être utilisé. En d'autres termes, n'utilisez pas ce modèle s'il recouvre un autre problème dans votre programme.
la source
Vous pouvez utiliser le modèle Builder comme le dit @JacquesB, ou bien penser pourquoi est-ce réellement que vos objets doivent être modifiables lors de la création?
En d'autres termes, pourquoi le processus de création doit-il être réparti dans le temps, au lieu de transmettre toutes les valeurs requises au constructeur et de créer des instances en une seule fois?
Parce que le constructeur peut être une bonne solution pour le mauvais problème.
Si le problème est que vous vous retrouvez avec un constructeur de 10 paramètres de long et que vous souhaitez l'atténuer en construisant l'objet petit à petit, cela pourrait indiquer que la conception est foirée, et ces 10 valeurs devraient être " ensachés "/ regroupés en quelques objets ... ou l'objet principal divisé en quelques plus petits ...
Dans ce cas - respectez l'immuabilité tout le temps, améliorez simplement la conception.
la source