1. Estático vs. instancia
Creo que hay pautas muy claras sobre qué es un buen diseño OO y qué no lo es. El problema es que la blogósfera hace que sea difícil separar lo bueno de lo malo y lo feo. Puede encontrar algún tipo de referencia que respalde incluso la peor práctica que se le ocurra.
Y la peor práctica que se me ocurre es el estado global, incluidas las estadísticas que mencionaste y el Singleton favorito de todos. Algunos extractos del clásico artículo de Misko Hevery sobre el tema .
Para comprender realmente las dependencias, los desarrolladores deben leer cada línea de código. Causa una acción espeluznante a distancia: cuando se ejecutan conjuntos de pruebas, el estado global mutado en una prueba puede hacer que una prueba posterior o paralela falle inesperadamente. Rompa la dependencia estática usando la inyección de dependencia manual o Guice.
La acción espeluznante a distancia es cuando ejecutamos una cosa que creemos que está aislada (ya que no pasamos ninguna referencia) pero se producen interacciones inesperadas y cambios de estado en ubicaciones distantes del sistema sobre las que no le informamos al objeto. Esto solo puede suceder a través del estado global.
Es posible que no lo haya pensado de esta manera antes, pero cada vez que usa un estado estático, está creando canales de comunicación secretos y no los deja claros en la API. Spooky Action at a Distance obliga a los desarrolladores a leer cada línea de código para comprender las posibles interacciones, reduce la productividad del desarrollador y confunde a los nuevos miembros del equipo.
Esto se reduce a que no debe proporcionar referencias estáticas a nada que tenga algún tipo de estado almacenado. El único lugar donde uso estadísticas estáticas es para constantes enumeradas, y tengo dudas sobre eso.
2. Métodos con parámetros de entrada y valores de retorno vs. métodos sin ninguno
Lo que debe tener en cuenta es que los métodos que no tienen parámetros de entrada ni parámetros de salida están garantizados para operar en algún tipo de estado almacenado internamente (de lo contrario, ¿qué están haciendo?). Hay idiomas enteros que se basan en la idea de evitar el estado almacenado.
Cada vez que haya almacenado el estado, tiene la posibilidad de efectos secundarios, así que asegúrese de usarlo siempre con atención. Esto implica que debe preferir funciones con entradas y / o salidas definidas.
Y, de hecho, las funciones que tienen entradas y salidas definidas son mucho más fáciles de probar: no tiene que ejecutar una función aquí e ir a mirar allí para ver qué sucedió, y no tiene que establecer una propiedad en alguna parte más antes de ejecutar la función bajo prueba.
También puede usar este tipo de función de forma segura como estática. Sin embargo, no lo haría, porque si luego quisiera usar una implementación ligeramente diferente de esa función en algún lugar, en lugar de proporcionar una instancia diferente con la nueva implementación, no tengo forma de reemplazar la funcionalidad.
3. Superposición vs. Distinción
No entiendo la pregunta. ¿Cuál sería la ventaja en 2 métodos superpuestos?
4. Privado vs. Público
No exponga nada que no necesite exponer. Sin embargo, tampoco soy un gran fanático de lo privado. No soy un desarrollador de C #, sino un desarrollador de ActionScript. Pasé mucho tiempo en el código de Adobe Flex Framework, que fue escrito alrededor del año 2007. Y tomaron algunas decisiones realmente malas sobre qué hacer privado, lo que hace que sea una pesadilla tratar de extender sus clases.
Entonces, a menos que piense que es un mejor arquitecto que los desarrolladores de Adobe alrededor del año 2007 (según su pregunta, diría que tiene unos años más antes de tener la oportunidad de hacer esa afirmación), es probable que solo desee usar la protección predeterminada .
Hay algunos problemas con sus ejemplos de código que significan que no están bien diseñados, por lo que no es posible elegir A o B.
Por un lado, probablemente debería separar la creación de su objeto de su uso . Por lo tanto, generalmente no tendría su new XMLReader()derecho al lado de donde se usa.
Además, como dice @djna, debe encapsular los métodos utilizados en los usos de su lector XML, de modo que su API (ejemplo de instancia) podría simplificarse para:
_document Document = reader.read(info);
No sé cómo funciona C #, pero dado que he trabajado con una serie de tecnologías web, sospecho que no siempre podrás devolver un documento XML de inmediato (excepto tal vez como una promesa o un tipo futuro objeto), pero no puedo darle consejos sobre cómo manejar una carga asincrónica en C #.
Tenga en cuenta que con este enfoque, puede crear varias implementaciones que pueden tomar un parámetro que les dice dónde / qué leer y devolver un objeto XML, y cambiarlos según las necesidades de su proyecto. Por ejemplo, puede estar leyendo directamente desde una base de datos, desde una tienda local o, como en su ejemplo original, desde una URL. No puede hacer eso si usa un método estático.