Hay una pequeña diferencia entre Java y C # que es relevante aquí. En Java, cada miembro es virtual por defecto. En C #, cada miembro está sellado de manera predeterminada, excepto los miembros de la interfaz.
Los supuestos que acompañan a esto influyen en la directriz: en Java, cada tipo público debe considerarse no final, de acuerdo con el Principio de sustitución de Liskov [1]. Si solo tiene una implementación, nombrará la clase Parser
; si encuentra que necesita implementaciones múltiples, simplemente cambiará la clase a una interfaz con el mismo nombre y cambiará el nombre de la implementación concreta a algo descriptivo.
En C #, la suposición principal es que cuando obtienes una clase (el nombre no comienza con I
), esa es la clase que deseas. Eso sí, esto no está cerca del 100% de precisión: un contraejemplo típico sería clases como Stream
(que realmente deberían haber sido una interfaz, o un par de interfaces), y todos tienen sus propias pautas y antecedentes de otros idiomas. También hay otras excepciones, como el Base
sufijo bastante utilizado para denotar una clase abstracta: al igual que con una interfaz, sabes que se supone que el tipo es polimórfico.
También hay una buena característica de usabilidad al dejar el nombre sin prefijo I para la funcionalidad que se relaciona con esa interfaz sin tener que recurrir a hacer de la interfaz una clase abstracta (lo que perjudicaría debido a la falta de herencia de clase múltiple en C #). Esto fue popularizado por LINQ, que utiliza IEnumerable<T>
como interfaz y Enumerable
como depósito de métodos que se aplican a esa interfaz. Esto es innecesario en Java, donde las interfaces también pueden contener implementaciones de métodos.
En última instancia, el I
prefijo se usa ampliamente en el mundo de C # y, por extensión, en el mundo de .NET (dado que la mayoría del código de .NET está escrito en C #, tiene sentido seguir las pautas de C # para la mayoría de las interfaces públicas). Esto significa que seguramente trabajará con bibliotecas y códigos que siguen esta notación, y tiene sentido adoptar la tradición para evitar confusiones innecesarias; no es como omitir el prefijo mejorará su código :)
Supongo que el razonamiento del tío Bob fue algo como esto:
IBanana
Es la noción abstracta de plátano. Si puede haber una clase de implementación que no tenga un nombre mejor que el Banana
, la abstracción no tiene ningún sentido, y debe abandonar la interfaz y simplemente usar una clase. Si hay un nombre mejor (digamos, LongBanana
o AppleBanana
), no hay razón para no usarlo Banana
como nombre de la interfaz. Por lo tanto, usar el I
prefijo significa que tiene una abstracción inútil, lo que hace que el código sea más difícil de entender sin ningún beneficio. Y dado que la OOP estricta siempre tendrá que codificar contra interfaces, el único lugar donde no vería el I
prefijo de un tipo sería en un constructor, un ruido bastante inútil.
Si aplica esto a su IParser
interfaz de muestra , puede ver claramente que la abstracción está completamente en el territorio "sin sentido". O bien hay algo específico acerca de una aplicación concreta de un programa de análisis (por ejemplo JsonParser
, XmlParser
, ...), o que sólo debe utilizar una clase. No existe tal cosa como "implementación predeterminada" (aunque en algunos entornos, esto tiene sentido, especialmente COM), ya sea que haya una implementación específica o que desee una clase abstracta o métodos de extensión para los "valores predeterminados". Sin embargo, en C #, a menos que su base de código ya omita el I
prefijo, guárdelo. Solo toma una nota mental cada vez que veas un código class Something: ISomething
, significa que alguien no es muy bueno siguiendo a YAGNI y construyendo abstracciones razonables.
[1] - Técnicamente, esto no se menciona específicamente en el documento de Liskov, pero es uno de los fundamentos del documento original de OOP y en mi lectura de Liskov, ella no cuestionó esto. En una interpretación menos estricta (la que toman la mayoría de los lenguajes OOP), esto significa que cualquier código que use un tipo público destinado a la sustitución (es decir, no final / sellado) debe funcionar con cualquier implementación conforme de ese tipo.