Je suis d'accord avec la réponse de Leandro. La programmation défensive est rarement la façon de faire Smalltalk. Il n'y a pas de typage statique pour appliquer quoi que ce soit, ni de messages privés. Smalltalk est ouvert et en retard. Mais d'un autre côté, les erreurs sont rarement catastrophiques (Smalltalk ne plante généralement pas en cas d'erreur).
Cette reliure tardive associée à une récupération d'erreur gracieuse est ce qui rend l'évolution du système très légère. Quand vous programmez dans Smalltalk, vous ne faites que faire évoluer le système live si vous y pensez.Puisque la seule chose que nous avons est d'envoyer des messages, nous pouvons éventuellement l'utiliser pour négocier les contrats, ou simplement vérifier une condition préalable.
La stratégie que vous suggérez est possible à travers l'utilisation d'Exception. L'idée est qu'il est parfois préférable d'avoir une Exception précoce la plus proche possible de la cause première, qu'une Exception tardive plus difficile à déboguer et à corriger. Voir par exemple le message #shouldNotImplement
et ses expéditeurs: vous verrez qu'il est parfois utilisé pour empêcher l'utilisation de #new
.
N'oubliez pas non plus qu'il existe un message #initialize
qui peut être utilisé pour donner une valeur par défaut raisonnable aux variables d'instance (un peu comme le constructeur par défaut de C++). Il existe des variantes lorsque vous souhaitez transmettre des informations supplémentaires: pour les collections qui sont généralement créées via #new:
, un message #initialize:
prend la taille comme argument. Vous pouvez affiner à volonté des mécanismes similaires pour passer d'autres informations à la création.
Mais n'essayez pas d'empêcher l'utilisation de #basicNew
. Vous créeriez de la douleur en interrompant certains services basés sur cette fonctionnalité de bas niveau, comme par exemple la mutation d'instances existantes lorsque vous modifiez la disposition de votre classe, comme la copie, le stockage dans des fichiers externes, etc ... par exemple #adoptInstance:
. Au lieu de cela, vous devez apprendre à faire confiance aux utilisateurs de votre bibliothèque (y compris vous-même): les utilisateurs n'utiliseront pas basicNew
à moins qu'ils sachent ce qu'ils font (ils apprendront cela tôt ou tard). Et comme l'a dit Amos, documentez les contrats et les attentes dans les commentaires de classe ou de message ou les tests unitaires, afin que les gens puissent apprendre plus rapidement, et peut-être utiliser des noms comme basicNew quand vous voulez exprimer un message.
EDIT en passant, si vous interdisez basicNew, vous ne serez pas en mesure de créer des instances du tout, donc vous devrez créer un nouveau message appelant la primitive pour créer une instance, et à la fin vous Il suffit d'avoir du code obscurci/complexifié pour rien, parce que vous venez de déplacer le problème. À moins que vous faites des choses très désagréables comme:
basicNew
thisContext sender method selector == #mySepcialCreationMessageWithParameter: ifTrue: [^super basicNew].
^self error: 'new instances should be created with mySepcialCreationMessageWithParameter:'
Comme je l'ai dit plus haut, vous pouvez jouer avec, mais ne le font pas pour de vrai. Un autre point de vue est que le codage est une activité sociale, et le code que vous écrivez dans Smalltalk ne sert pas seulement à programmer un automate. C'est pour être lu et réutilisé par les humains. Dans ce contexte, la programmation défensive est un peu comme la gestion par coercition. Au lieu de perdre du temps à essayer de contraindre, il est plus efficace de passer du temps à créer des abstractions simples et logiques qui peuvent être facilement comprises et réutilisées, peut-être dans d'autres contextes que vous n'aviez pas prévus.
Je recommanderais l'option # 3. La seule chose que vous, en tant qu'auteur d'un objet, pourriez (et en fait devrait) faire est d'ajouter votre hypothèse au commentaire de classe. Si vous ajoutez quelque chose comme "Je m'attends à être instancié aveC#newWith: - si vous créez une instance de moi en utilisant #new ou #basicNew, des choses étranges peuvent arriver", alors vous avez fait votre part et tout problème survenant Des instanciations inappropriées/inattendues sont la responsabilité de la personne qui utilise votre objet. Essayer d'anticiper toutes les manières possibles que quelqu'un puisse faire quelque chose de bizarre signifie commencer une bataille que vous perdrez probablement. ;-) –
isValidInContext: anApplicationContext est très utile au niveau de l'application. –