language-agnostic - girona - tutorial qgis 2.18 español pdf
¿Las dependencias de clase circular son malas desde el punto de vista del estilo de codificación? (7)
¿Las dependencias de clase circular son malas desde el punto de vista del estilo de codificación?
Ejemplo:
En una aplicación de base de datos tenemos dos clases, una que encapsula información sobre una base de datos única ( DBInfo
) y una clase que puede crear una conexión de base de datos. ( ConnFactory
)
DBInfo
tiene un método getConnection
que utiliza ConnFactory
para crear una conexión. Pero ConnFactory
necesita un objeto DBInfo
para hacerlo.
Así: (Cualquier estilo de codificación que no se tenga en cuenta por motivos de legibilidad)
class DBInfo {
String name;
String connectionUrl;
Connection getConnection() {
return ConnFactory.getConnection(this);
}
}
class ConnFactory {
Connection getConnection(DBInfo toWhat) {
return new Connection(toWhat.connectionUrl);
}
}
Mis compañeros de trabajo argumentan que esta es una mala práctica y sería mejor si hubiera solo una dirección de dependencias y no circulares, como aquí.
¿Es esta mala práctica, un anti-patrón o un olor de código? ¿Hay algún inconveniente?
¿Qué pasa con una relación bidireccional de uno a muchos que es un caso tan común en cualquier aplicación que utiliza una capa ORM? ¿No es este un caso de una dependencia circular?
¿Es malo / olor de código?
En general, llamaría a las dependencias circulares un Code Smell. Tenga en cuenta que el término ''Olfato de código'' indica principalmente que ''aquí hay un código que requiere atención especial y es probable que se beneficie del rediseño''.
En la mayoría de los casos, consideraría firmemente un diseño en el que no sea necesaria una dependencia circular, pero en casos raros puede estar bien.
En su ejemplo, el ConnFactory parece redundante, pero eso puede deberse a que su ejemplo ha sido recortado. Sin embargo, me parece que la lógica de creación de la Conexión sería mejor si se moviera a la clase DBInfo. Cuando ya tiene una clase que contiene datos sobre una base de datos, parece natural que se haga responsable de crear una conexión a esa base de datos.
Este código solo funciona si ConnFactory.getConnection()
es estático. Una mejor solución sería hacer que getConnection()
un método de instancia de ConnFactory
. Entonces su DBInfo puede tomar un ConnFactory
como un argumento (posiblemente en un constructor, si tiene un constructor sobrecargado). Sin embargo, creo que el uso del método estático para este caso es más una mala práctica que la referencia circular.
Sin embargo, si tuviera que seguir esta ruta, también haría una interfaz IConnFactory
que DBInfo
interactuaría y que implementaría ConnFactory
. Entonces no hay una referencia circular: tanto DBInfo
como ConnFactory
dependerían de IConnFactory
, que no dependería de ninguno.
Las dependencias circulares son malas porque:
- dos dependencias es mas de una
- no se puede probar de forma incremental (sin burlarse de uno de ellos, lo cual sería una tontería para cosas pequeñas y muy relacionadas).
Puede hacer todas las cosas con interfaces para romper la dependencia circular si es necesario, pero la solución mínima es simplemente hacer de DBInfo una clase anidada de ConnFactory. Una unidad que se hace referencia a sí misma no es circular.
Lo único que sé es que las dependencias circulares pueden convertirse en un pequeño problema cuando comienza a utilizar un Marco de inyección de dependencias, como el Mapa de estructura. La mayoría de estos marcos tienen problemas para manejar las dependencias circulares, lo que a veces resulta en una excepción de desbordamiento de pila (perdón por el juego de palabras :-)) Por lo tanto, tiendo a tratar de evitarlo a menos que sea absolutamente necesario y no se pueda evitar.
Sí, en general las dependencias circulares son malas, aunque no siempre malas. Los problemas con las dependencias circulares incluyen acoplamiento apretado, módulos mutuamente dependientes y generalmente efecto dominó, cuando los cambios en un módulo se propagan a otros módulos.
Dicho esto, su código está violando el principio de responsabilidad única, ya que DBInfo
no solo almacena información sobre la base de datos, sino que también es responsable de obtener objetos de Connection
. Quita esa pieza particular de funcionalidad a una clase separada y todo estará bien.
No necesariamente
No creo que las dependencias circulares en el nivel de granularidad de clase sean malas. No veo un problema si dos, tres o quizás cuatro clases son mutuamente dependientes. (No estoy diciendo que esto es algo que quieres, pero puede estar bien en algunas circunstancias).
Es un problema si tiene dependencia mutua a nivel de paquete o módulo, por todas las razones mencionadas arriba y abajo.