programación - Interfaces Java/convención de nomenclatura de implementación
ejercicios resueltos de clases abstractas en java (9)
Esta pregunta ya tiene una respuesta aquí:
- Nombre de la interfaz en Java [cerrado] 11 respuestas
¿Cómo nombras las diferentes clases / interfaces que creas? A veces no tengo información de implementación para agregar al nombre de la implementación, como la interfaz FileHandler
y la clase SqlFileHandler
.
Cuando esto sucede, normalmente TruckClass
la interfaz con el nombre "normal", como Truck
y TruckClass
clase real TruckClass
.
¿Cómo nombrar interfaces y clases en este sentido?
A algunas personas no les gusta esto, y es más una convención .NET que Java, pero puedes nombrar tus interfaces con un prefijo de mayúsculas, por ejemplo:
IProductRepository - interface
ProductRepository, SqlProductRepository, etc. - implementations
Las personas que se oponen a esta convención de nomenclatura podrían argumentar que no debería importarte si trabajas con una interfaz o un objeto en tu código, pero me resulta más fácil leer y entender sobre la marcha.
No nombraría la clase de implementación con un sufijo "Clase". Eso puede llevar a confusión, porque en realidad puede trabajar con objetos de "clase" (es decir, Tipo) en su código, pero en su caso, no está trabajando con el objeto de clase, simplemente está trabajando con un objeto antiguo. .
El nombre de la interfaz debe describir el concepto abstracto que representa la interfaz. Cualquier clase de implementación debe tener algún tipo de rasgos específicos que puedan usarse para darle un nombre más específico.
Si solo hay una clase de implementación y no puede pensar en nada que la haga específica (implícito al querer nombrarla -Impl
), entonces parece que no hay justificación para tener una interfaz.
He visto respuestas aquí que sugieren que si solo tiene una implementación, no necesita una interfaz. Esto va en contra del principio de Inyección / Inversión de Control de Depencencia (¡No nos llame, le llamaremos!).
Entonces, sí, hay situaciones en las que desea simplificar su código y hacerlo fácilmente verificable al basarse en implementaciones de interfaz inyectadas (que también pueden ser sustituidas por proxy, ¡su código no lo sabe!). Incluso si solo tiene dos implementaciones, una simulacro de prueba y otra que se inyecta en el código de producción real, esto no hace que tener una interfaz sea superflua. Una interfaz bien documentada establece un contrato, que también puede ser mantenido por una estricta implementación simulada para pruebas.
de hecho, puede establecer pruebas que imiten la implementación del contrato de interfaz más estricto (lanzar excepciones para argumentos que no deben ser nulos, etc.) y detectar errores en las pruebas, utilizando una implementación más eficiente en el código de producción (sin verificar los argumentos que deberían no ser nulo por ser nulo ya que el simulacro arrojó excepciones en sus pruebas y sabe que los argumentos no son nulos debido a la corrección del código después de estas pruebas, por ejemplo).
La inyección de dependencia / COI puede ser difícil de captar para un recién llegado, pero una vez que comprenda su potencial, querrá usarlo por todas partes y se encontrará haciendo interfaces todo el tiempo, incluso si solo habrá uno ( producción real) implementación.
Para esta única implementación (puede inferir, y sería correcto, que creo que los simulacros de prueba deberían llamarse Simulacros (Nombre de Interfaz)), prefiero el nombre Predeterminado (Nombre de Interfaz). Si se presenta una implementación más específica, se puede nombrar de manera apropiada. Esto también evita el sufijo Impl que particularmente me disgusta (si no es una clase abstracta, ¡POR SUPUESTO es una "implícita"!).
También prefiero "Base (InterfaceName)" en lugar de "Abstract (InterfaceName)" porque hay algunas situaciones en las que quieres que tu clase base se convierta en instanciable más adelante, pero ahora estás atrapado con el nombre "Abstract (InterfaceName)" , y esto te obliga a cambiar el nombre de la clase, posiblemente causando una pequeña confusión, pero si siempre fue Base (Nombre de Interfaz), eliminar el modificador abstracto no cambia lo que era la clase.
La convención estándar de C #, que también funciona bastante bien en Java, es prefijar todas las interfaces con una I
, por lo que su interfaz de manejador de archivos será IFileHandler
y su interfaz de camión será ITruck
. Es consistente, y hace que sea fácil distinguir las interfaces de las clases.
Me gustan los nombres de interfaz que indican qué contrato describe una interfaz, como "Comparable" o "Serializable". Los nombres como "Camión" en realidad no describen la habilidad del camión. ¿Cuáles son las habilidades de un camión?
Con respecto a las convenciones: he trabajado en proyectos donde cada interfaz comienza con una "I"; Si bien esto es un tanto ajeno a las convenciones de Java, hace que encontrar interfaces sea muy fácil. Aparte de eso, el sufijo "Impl" es un nombre predeterminado razonable.
Nombre su Interface
lo que es. Truck
No es ITruck
porque no es un ITruck
, es un Truck
.
Una Interface
en Java es un Type . Luego tienes DumpTruck
, TransferTruck
, WreckerTruck
, CementTruck
, etc. que implement Truck
.
Cuando está utilizando la Interface
en lugar de una subclase, simplemente la envía a Truck
. Como en la List<Truck>
. Poner al frente es solo tautology notación de estilo húngaro que no agrega nada más que escribir en su código.
Todos los modernos IDE de Java marcan Interfaces e Implementaciones y no de esta notación tonta. No lo llame TruckClass
que es una tautology tan mala como la tautología IInterface
.
Si es una implementación es una clase. La única excepción real a esta regla, y siempre hay excepciones, podría ser algo como AbstractTruck
. Dado que solo las subclases verán esto y nunca se debe convertir en una clase Abstract
, se agrega cierta información de que la clase es abstracta y cómo debe usarse. Aún podrías tener un nombre mejor que AbstractTruck
y usar BaseTruck
o DefaultTruck
lugar de que el abstract
está en la definición. Pero dado que las clases Abstract
nunca deben ser parte de ninguna interfaz pública, creo que es una excepción aceptable a la regla. Hacer que los constructores protected
pasen un largo camino para cruzar esta división.
Y el sufijo Impl
es solo más ruido también. Más tautología. Cualquier cosa que no sea una interfaz es una implementación, incluso clases abstractas que son implementaciones parciales. ¿Vas a poner ese tonto sufijo Impl
en cada nombre de cada Class ?
La Interface
es un contrato sobre lo que los métodos y las propiedades públicas tienen que soportar, también es información de Type . Todo lo que implementa Truck
es un Type de Truck
.
Mira a la biblioteca estándar de Java en sí. ¿Ves IList
, ArrayListImpl
, LinkedListImpl
? No, ves List
y ArrayList
, y LinkedList
. Aquí hay un buen article sobre esta pregunta exacta. Cualquiera de estas convenciones de nomenclatura de prefijos / sufijos tontos también violan el principio DRY .
Además, si se encuentra agregando DTO
, JDO
, BEAN
u otros sufijos repetitivos tontos a los objetos, probablemente pertenezcan a un package lugar de a todos esos sufijos. Los espacios de nombres correctamente empaquetados se autodocumentan y reducen toda la información redundante inútil en estos esquemas de nombres patentados realmente mal concebidos que la mayoría de los lugares ni siquiera se adhieren internamente de manera consistente.
Si todo lo que puede hacer para que su nombre de Class
único es su sufijo con Impl
, entonces debe volver a pensar en tener una Interface
. Por lo tanto, cuando tiene una situación en la que tiene una Interface
y una Implementation
única que no está especializada únicamente en la Interface
, probablemente no necesite la Interface
.
Tiendo a seguir las pseudo convenciones establecidas por Java Core / Sun, por ejemplo, en las clases de Colecciones:
-
List
- interfaz para el objeto "conceptual" -
ArrayList
- implementación concreta de la interfaz -
LinkedList
- implementación concreta de la interfaz -
AbstractList
- implementación abstracta "parcial" para ayudar a implementaciones personalizadas
Solía hacer lo mismo modelando mis clases de eventos después del paradigma AWT Event / Listener / Adapter.
Yo uso ambas convenciones:
Si la interfaz es una instancia específica de un patrón bien conocido (p. Ej., Servicio, DAO), es posible que no necesite una "I" (p. Ej. UserService, AuditService, UserDao) que todo funcione bien sin la "I", porque determina el patrón meta.
Pero, si tiene algo de una vez o dos (generalmente para un patrón de devolución de llamada), entonces es útil distinguirlo de una clase (por ejemplo, IAsynchCallbackHandler, IUpdateListener, IComputeDrone). Estas son interfaces de propósito especial diseñadas para uso interno. En ocasiones, el Interfaz II llama la atención sobre el hecho de que un operando es en realidad una interfaz, por lo que a primera vista queda claro de inmediato.
En otros casos, puede usar la I para evitar chocar con otras clases concretas conocidas (ISubject, IPrincipal vs Subject o Principal).
TruckClass
suena como si fuera una clase de Truck
, creo que la solución recomendada es agregar el sufijo Impl
. En mi opinión, la mejor solución es contener información sobre el nombre de la implementación, lo que está sucediendo en esa implementación en particular (como la que tenemos con la interfaz de List
y las implementaciones: ArrayList
o LinkedList
), pero a veces solo tiene una implementación y debe tener la interfaz necesaria. Para uso remoto (por ejemplo), entonces (como se mencionó al principio) Impl
es la solución.