1. Statico vs. istanza
Penso che ci siano linee guida molto chiare su cosa sia un buon design OO e cosa no. Il problema è che la blogosfera rende difficile separare il buono dal cattivo e il cattivo. Puoi trovare una sorta di riferimento a supporto anche della peggiore pratica che ti viene in mente.
E la peggior pratica che mi viene in mente è lo stato globale, comprese le statistiche che hai citato e il Singleton preferito da tutti. Alcuni estratti del classico articolo di Misko Hevery sull'argomento .
Per comprendere veramente le dipendenze, gli sviluppatori devono leggere ogni riga di codice. Provoca un'azione spettrale a distanza: quando si eseguono suite di test, lo stato globale mutato in un test può causare il fallimento inaspettato di un test successivo o parallelo. Rompere la dipendenza statica usando l'iniezione manuale o Guice.
L'azione spettrale a distanza è quando eseguiamo una cosa che crediamo sia isolata (dal momento che non abbiamo passato alcun riferimento) ma interazioni impreviste e cambiamenti di stato avvengono in posizioni distanti del sistema di cui non abbiamo parlato con l'oggetto. Questo può avvenire solo tramite lo stato globale.
Forse non ci hai mai pensato prima, ma ogni volta che usi lo stato statico, crei canali di comunicazione segreti e non li chiarisci nell'API. Spooky Action at a Distance costringe gli sviluppatori a leggere ogni riga di codice per comprendere le potenziali interazioni, ridurre la produttività degli sviluppatori e confondere i nuovi membri del team.
Ciò si riduce al fatto che non è necessario fornire riferimenti statici a qualsiasi cosa che abbia una sorta di stato memorizzato. L'unico posto in cui uso la statica è per le costanti enumerate, e ho dei dubbi anche su questo.
2. Metodi con parametri di input e valori di ritorno vs. metodi con nessuno
La cosa che devi capire è che i metodi che non hanno parametri di input e parametri di output sono praticamente garantiti per funzionare su una sorta di stato memorizzato internamente (altrimenti, cosa stanno facendo?). Ci sono intere lingue che si basano sull'idea di evitare lo stato memorizzato.
Ogni volta che hai uno stato memorizzato, hai la possibilità di effetti collaterali, quindi assicurati di usarlo sempre consapevolmente. Questo implica che dovresti preferire le funzioni con input e / o output definiti.
E, in effetti, le funzioni che hanno definito ingressi e uscite sono molto più facili da testare: non è necessario eseguire una funzione qui e andare lì per vedere cosa è successo e non è necessario impostare una proprietà da qualche parte altrimenti prima di eseguire la funzione sotto test.
È inoltre possibile utilizzare questo tipo di funzione in modo sicuro come statica. Tuttavia, non lo farei, perché se in seguito volessi utilizzare un'implementazione leggermente diversa di quella funzione da qualche parte, piuttosto che fornire un'istanza diversa con la nuova implementazione, sono bloccato senza alcun modo per sostituire la funzionalità.
3. Sovrapposizione vs. distinta
Non capisco la domanda. Quale sarebbe il vantaggio in 2 metodi sovrapposti?
4. Privato vs. Pubblico
Non esporre nulla che non è necessario esporre. Tuttavia, non sono neanche un grande fan del privato. Non sono uno sviluppatore C #, ma uno sviluppatore ActionScript. Ho trascorso molto tempo nel codice Adobe Flex Framework, che è stato scritto intorno al 2007. E hanno fatto delle scelte davvero sbagliate su cosa rendere privato, il che rende un incubo cercare di estendere le loro lezioni.
Quindi, a meno che tu non pensi di essere un architetto migliore degli sviluppatori Adobe intorno al 2007 (dalla tua domanda, direi che hai ancora qualche anno prima che tu abbia la possibilità di avanzare tale pretesa), probabilmente vorrai semplicemente impostare come protetto .
Ci sono alcuni problemi con i tuoi esempi di codice che indicano che non sono ben progettati, quindi non è possibile scegliere A o B.
Per prima cosa, probabilmente dovresti separare la creazione del tuo oggetto dal suo uso . Quindi di solito non avresti il new XMLReader()
diritto proprio accanto a dove viene utilizzato.
Inoltre, come dice @djna, dovresti incapsulare i metodi utilizzati nei tuoi XML Reader, quindi la tua API (esempio di istanza) potrebbe essere semplificata per:
_document Document = reader.read(info);
Non so come funzioni C #, ma dal momento che ho lavorato con una serie di tecnologie Web, sarei sospettoso che non saresti sempre in grado di restituire immediatamente un documento XML (tranne forse come una promessa o un tipo futuro oggetto), ma non posso darti consigli su come gestire un carico asincrono in C #.
Si noti che con questo approccio, è possibile creare diverse implementazioni che possono prendere un parametro che dice loro dove / cosa leggere e restituire un oggetto XML e scambiarli in base alle esigenze del progetto. Ad esempio, potresti leggere direttamente da un database, da un negozio locale o, come nell'esempio originale, da un URL. Non puoi farlo se usi un metodo statico.