Contexte
J'ai actuellement une situation où j'ai un objet qui est à la fois transmis et reçu par un appareil. Ce message a plusieurs constructions, comme suit:
public void ReverseData()
public void ScheduleTransmission()
La ScheduleTransmission
méthode doit appeler la ReverseData
méthode chaque fois qu'elle est appelée. Cependant, il y a des moments où je ReverseData
devrai appeler en externe (et je devrais ajouter entièrement en dehors de l'espace de noms ) d'où l'objet est instancié dans l'application.
Quant au "recevoir", je veux dire qu'il ReverseData
sera appelé en externe dans un object_received
gestionnaire d'événements pour annuler les données.
Question
Est-il généralement acceptable qu'un objet appelle ses propres méthodes publiques?
c#
design-patterns
object-oriented
methods
Fouiner
la source
la source
Réponses:
Je dirais que ce n'est pas seulement acceptable, mais encouragé, surtout si vous prévoyez d'autoriser des extensions. Afin de prendre en charge les extensions de la classe en C #, vous devez marquer la méthode comme virtuelle selon les commentaires ci-dessous. Vous voudrez peut-être documenter cela, cependant, afin que quelqu'un ne soit pas surpris lorsque le remplacement de ReverseData () modifie le fonctionnement de ScheduleTransmission ().
Cela se résume vraiment à la conception de la classe. ReverseData () ressemble à un comportement fondamental de votre classe. Si vous devez utiliser ce comportement à d'autres endroits, vous ne voudrez probablement pas en avoir d'autres versions. Vous devez juste faire attention à ne pas laisser les détails spécifiques à ScheduleTransmission () s'infiltrer dans ReverseData (). Cela va créer des problèmes. Mais puisque vous l'utilisez déjà en dehors de la classe, vous y avez probablement déjà pensé.
la source
ReverseData()
soit abstrait, peu importe ce que vous faites dans la classe enfant, c'est toujours la méthode originale qui sera appelée.virtual
... Et si vous remplacez la méthode, alors par définition, elle doit êtrevirtual
ouabstract
.virtual
marche aussi. Dans tous les cas, la signature, selon OP, estpublic void ReverseData()
, donc la partie de la réponse sur les choses primordiales est légèrement trompeuse.abstract
? J'ai recherché des réponses surabstract
vsvirtual
et je n'ai pas vu cela mentionné: plutôt abstrait signifie simplement qu'il n'y a pas de version donnée dans cette base.Absolument.
La visibilité d'une méthode a pour seul but d'autoriser ou de refuser l'accès à une méthode en dehors de la classe ou au sein d'une classe enfant; Les méthodes publiques, protégées et privées peuvent toujours être appelées à l'intérieur de la classe elle-même.
Il n'y a rien de mal à appeler des méthodes publiques. L'illustration de votre question est l'exemple parfait d'une situation où avoir deux méthodes publiques est exactement ce que vous devez faire.
Cependant, vous pouvez surveiller attentivement les modèles suivants:
Une méthode
Hello()
appelleWorld(string, int, int)
comme ceci:Évitez ce schéma. Utilisez plutôt des arguments facultatifs . Les arguments facultatifs facilitent la découverte: l'appelant qui tape
Hello(
ne sait pas nécessairement qu'il existe une méthode qui permet d'appeler la méthode avec des valeurs par défaut. Les arguments facultatifs sont également auto-documentés.World()
ne montre pas à l'appelant quelles sont les valeurs par défaut réelles.Une méthode
Hello(ComplexEntity)
appelleWorld(string, int, int)
comme ceci:Utilisez plutôt des surcharges . Même raison: meilleure découvrabilité. L'appelant peut voir à la fois toutes les surcharges via IntelliSense et choisir la bonne.
Une méthode appelle simplement d'autres méthodes publiques sans ajouter de valeur substantielle.
Réfléchissez bien. Avez-vous vraiment besoin de cette méthode? Ou devez-vous le supprimer et laisser l'appelant invoquer les différentes méthodes? Un conseil: si le nom de la méthode ne semble pas correct ou est difficile à trouver, vous devriez probablement le supprimer.
Une méthode valide l'entrée et appelle ensuite l'autre méthode:
Au lieu de cela,
World
devrait valider ses paramètres lui-même ou être privé.la source
Si quelque chose est public, il peut être appelé à tout moment par n'importe quel système. Il n'y a aucune raison pour que vous ne puissiez pas être l'un de ces systèmes aussi!
Dans les bibliothèques hautement optimisées, vous souhaitez copier l'idiome mis en avant
java.util.ArrayList#ensureCapacity(int)
.assurerCapacité
ensureCapacity
est publicensureCapacity
a toutes les limites nécessaires de vérification et de valeurs par défaut, etc.ensureCapacity
appelsensureExplicitCapacity
assureCapacitéInterne
ensureCapacityInternal
est privéensureCapacityInternal
a une vérification d'erreur minimale car toutes les entrées proviennent de l'intérieur de la classeensureCapacityInternal
Appelle AUSSIensureExplicitCapacity
assureExplicitCapacity
ensureExplicitCapacity
est AUSSI privéensureExplicitCapacity
n'a pas de vérification d'erreurensureExplicitCapacity
fait du vrai travailensureExplicitCapacity
n'est appelé de nulle part sauf parensureCapacity
etensureCapacityInternal
De cette façon, le code en lequel vous avez confiance obtient un accès privilégié (et plus rapide!) Car vous savez que ses entrées sont bonnes. Le code auquel vous ne faites pas confiance passe par une certaine rigueur pour vérifier son intégrité et bombarder ou fournir des valeurs par défaut ou gérer autrement de mauvaises entrées. Tous deux se dirigent vers l'endroit qui fonctionne réellement.
Cependant, cela est utilisé dans ArrayList, l'une des classes les plus utilisées dans le JDK. Il est très possible que votre cas ne nécessite pas ce niveau de complexité et de rigueur. Pour faire court, si tous les
ensureCapacityInternal
appels étaient remplacés par desensureCapacity
appels, les performances seraient toujours vraiment, vraiment bonnes. Il s'agit d'une microoptimisation qui n'a probablement été réalisée qu'après mûre réflexion.la source
Plusieurs bonnes réponses ont déjà été données, et je suis également d'accord avec elles sur le fait qu'un objet peut appeler ses méthodes publiques à partir de ses autres méthodes. Cependant, il y a une légère mise en garde de conception que vous devrez surveiller.
Les méthodes publiques ont généralement un contrat de "prendre l'objet dans un état cohérent, faire quelque chose de sensé, laisser l'objet dans un état cohérent (éventuellement différent)". Ici, «cohérent» peut signifier, par exemple, que le
Length
de aList<T>
n'est pas supérieur au sienCapacity
et que référencer les éléments aux indices de0
àLength-1
ne lancera pas.Mais à l'intérieur des méthodes de l'objet, l'objet peut être dans un état incohérent, donc lorsque vous appelez l'une de vos méthodes publiques, cela peut faire une très mauvaise chose, car il n'a pas été écrit avec une telle possibilité à l'esprit. Donc, si vous prévoyez d'appeler vos méthodes publiques à partir de vos autres méthodes, assurez-vous que leur contrat est "prenez l'objet dans un état, faites quelque chose de sensé, laissez l'objet dans un (peut-être différent) (peut-être incohérent - mais seulement si l'initiale état incohérent) ".
la source
Un autre exemple lorsque l'appel d'une méthode publique à l'intérieur d'une autre méthode publique est tout à fait correct est une approche CanExecute / Execute. Je l'utilise lorsque j'ai besoin à la fois d'une validation et d'une conservation invariante .
Mais en général, je suis toujours prudent à ce sujet. Si une méthode
a()
est appelée méthode insideb()
, cela signifie qu'ellea()
est un détail d'implémentation deb()
. Très souvent, cela indique qu'ils appartiennent à différents niveaux d'abstraction. Et le fait qu'ils soient tous les deux publics me fait me demander s'il s'agit ou non d'une violation du principe de responsabilité unique .la source
Désolé mais je vais devoir être en désaccord avec la plupart des autres réponses «oui vous pouvez» et dire que:
Je découragerais une classe d'appeler une méthode publique d'une autre
Il y a quelques problèmes potentiels avec cette pratique.
1: boucle infinie dans la classe héritée
Ainsi, votre classe de base appelle method1 de method2 mais vous ou quelqu'un d'autre en héritez et cache method1 avec une nouvelle méthode qui appelle method2.
2: événements, journalisation, etc.
par exemple, j'ai une méthode Add1 qui déclenche un événement '1 ajouté!' Je ne veux probablement pas que la méthode Add10 déclenche cet événement, écrive dans un journal ou autre, dix fois.
3: filetage et autres blocages
Par exemple, InsertComplexData ouvre une connexion db, démarre une transaction, verrouille une table, puis appelle InsertSimpleData, avec ouvre une connexion, démarre une transaction, attend que la table soit déverrouillée ....
Je suis sûr qu'il y a plus de raisons, l'une des autres réponses a abordé `` vous modifiez la méthode1 et vous êtes surpris que la méthode2 commence à se comporter différemment ''
En général, si vous avez deux méthodes publiques qui partagent du code, il vaut mieux les faire appeler toutes les deux une méthode privée plutôt que l'une d'appeler l'autre.
Modifier ----
Permet d'étendre le cas spécifique du PO.
nous n'avons pas beaucoup de détails mais nous savons que ReverseData est appelé par un gestionnaire d'événements d'une certaine sorte ainsi que par la méthode ScheduleTransmission.
Je suppose que les données inversées modifient également l'état interne de l'objet
Dans ce cas, je pense que la sécurité des fils serait importante et c'est pourquoi ma troisième objection à la pratique s'applique.
Pour sécuriser le thread ReverseData, vous pouvez ajouter un verrou. Mais si ScheduleTransmission doit également être sûr pour les threads, vous souhaiterez partager le même verrou.
La façon la plus simple de procéder consiste à déplacer le code ReverseData dans une méthode privée et à ce que les deux méthodes publiques l'appellent. Vous pouvez ensuite placer l'instruction lock dans les méthodes publiques et partager un objet lock.
De toute évidence, vous pouvez dire "cela n'arrivera jamais!" ou "Je pourrais programmer la serrure d'une autre manière" mais le point essentiel d'une bonne pratique de codage est de bien structurer votre code en premier lieu.
En termes académiques, je dirais que cela viole le L en solide. Les méthodes publiques sont plus que simplement accessibles au public. Ils sont également modifiables par ses héritiers. Votre code doit être fermé pour modification, ce qui signifie que vous devez réfléchir à votre travail dans les méthodes publiques et protégées.
En voici un autre: vous violez également potentiellement DDD. Si votre objet est un objet de domaine, ses méthodes publiques doivent être des termes de domaine qui signifient quelque chose pour l'entreprise. Dans ce cas, il est très peu probable que «acheter une douzaine d'œufs» soit la même chose que «acheter 1 œuf 12 fois» même si cela commence de cette façon.
la source