1. Statique vs instance
Je pense qu'il existe des directives très claires sur ce qu'est une bonne conception OO et ce qui ne l'est pas. Le problème est que la blogosphère rend difficile de séparer le bon du mauvais et du laid. Vous pouvez trouver une sorte de référence soutenant même la pire pratique à laquelle vous pouvez penser.
Et la pire pratique à laquelle je peux penser est Global State, y compris les statistiques que vous avez mentionnées et le Singleton préféré de tout le monde. Quelques extraits de l' article classique de Misko Hevery sur le sujet .
Pour vraiment comprendre les dépendances, les développeurs doivent lire chaque ligne de code. Cela provoque une action effrayante à distance: lors de l'exécution de suites de tests, l'état global muté dans un test peut entraîner l'échec inattendu d'un test ultérieur ou parallèle. Brisez la dépendance statique à l'aide d'une injection de dépendance manuelle ou Guice.
L'action fantasmagorique à distance est lorsque nous exécutons une chose que nous croyons isolée (puisque nous n'avons transmis aucune référence), mais des interactions et des changements d'état inattendus se produisent dans des endroits éloignés du système dont nous n'avons pas parlé à l'objet. Cela ne peut se produire que via l'état global.
Vous ne l'avez peut-être pas pensé de cette façon auparavant, mais chaque fois que vous utilisez un état statique, vous créez des canaux de communication secrets et ne les rendez pas clairs dans l'API. Une action fantasmagorique à distance oblige les développeurs à lire chaque ligne de code pour comprendre les interactions potentielles, réduit la productivité des développeurs et confond les nouveaux membres de l'équipe.
Cela revient à dire que vous ne devez pas fournir de références statiques à tout ce qui a une sorte d'état stocké. Le seul endroit où j'utilise la statique est pour les constantes énumérées, et j'ai des doutes à ce sujet.
2. Méthodes avec paramètres d'entrée et valeurs de retour vs méthodes sans aucun
La chose que vous devez comprendre est que les méthodes qui n'ont ni paramètres d'entrée ni paramètres de sortie sont à peu près garanties de fonctionner sur une sorte d'état stocké en interne (sinon, que font-elles?). Il existe des langages entiers qui sont construits sur l'idée d'éviter l'état stocké.
Chaque fois que vous avez stocké l'état, vous avez la possibilité d'effets secondaires, alors assurez-vous de toujours l'utiliser en pleine conscience. Cela implique que vous devriez préférer les fonctions avec des entrées et / ou sorties définies.
Et, en fait, les fonctions qui ont des entrées et des sorties définies sont beaucoup plus faciles à tester - vous n'avez pas besoin d'exécuter une fonction ici et d'aller là-bas pour voir ce qui s'est passé, et vous n'avez pas besoin de définir une propriété quelque part sinon avant d'exécuter la fonction en cours de test.
Vous pouvez également utiliser en toute sécurité ce type de fonction comme statique. Cependant, je ne le ferais pas, car si je voulais ensuite utiliser une implémentation légèrement différente de cette fonction quelque part, plutôt que de fournir une instance différente avec la nouvelle implémentation, je suis coincé sans aucun moyen de remplacer la fonctionnalité.
3. Chevauchement vs Distinction
Je ne comprends pas la question. Quel serait l'avantage de 2 méthodes qui se chevauchent?
4. Privé vs public
N'exposez rien que vous n'avez pas besoin d'exposer. Cependant, je ne suis pas non plus un grand fan du privé. Je ne suis pas un développeur C #, mais un développeur ActionScript. J'ai passé beaucoup de temps dans le code Flex Framework d'Adobe, qui a été écrit vers 2007. Et ils ont fait de très mauvais choix sur ce qui devait être privé, ce qui en fait une sorte de cauchemar à essayer d'étendre leurs classes.
Donc, à moins que vous ne pensiez être un meilleur architecte que les développeurs d'Adobe vers 2007 (d'après votre question, je dirais que vous avez encore quelques années avant d'avoir la possibilité de faire cette affirmation), vous voudrez probablement simplement utiliser par défaut la protection .
Il y a quelques problèmes avec vos exemples de code qui signifient qu'ils ne sont pas bien architecturés, il n'est donc pas possible de choisir A ou B.
D'une part, vous devriez probablement séparer la création de votre objet de son utilisation . Donc, vous n'auriez généralement pas votre new XMLReader()
droit à côté de l'endroit où il est utilisé.
En outre, comme le dit @djna, vous devez encapsuler les méthodes utilisées dans vos utilisations de XML Reader, afin que votre API (exemple d'instance) puisse être simplifiée pour:
_document Document = reader.read(info);
Je ne sais pas comment C # fonctionne, mais comme j'ai travaillé avec un certain nombre de technologies Web, je soupçonnerais que vous ne seriez pas toujours en mesure de renvoyer un document XML immédiatement (sauf peut-être comme promesse ou type futur) objet), mais je ne peux pas vous donner de conseils sur la façon de gérer une charge asynchrone en C #.
Notez qu'avec cette approche, vous pouvez créer plusieurs implémentations qui peuvent prendre un paramètre qui leur indique où / quoi lire et retourner un objet XML, et les échanger en fonction des besoins de votre projet. Par exemple, vous pouvez lire directement à partir d'une base de données, d'un magasin local ou, comme dans votre exemple d'origine, d'une URL. Vous ne pouvez pas faire cela si vous utilisez une méthode statique.