Estoy desarrollando una API RESTful y creo que es conveniente usar DAO para mis recursos porque aunque planeo usar solo memoria para almacenarlos, no quiero cerrar la puerta a quien esté usando mi biblioteca si deciden usar Una implementación de base de datos para el DAO.
Mi pregunta es si el DAO debería ser un singleton o no. Si no es así, el servicio tendrá una instancia del DAO y se vería más o menos así:
@Path("eventscheduler")
public class EventSchedulerService {
private IEventSchedulerDao dao = new EventSchedulerDao();
// in case a different implementation is to be used
public void setEventSchedulerDao(IEventSchedulerDao dao) {
this.dao = dao;
}
@Path("{uniqueName}")
@GET
@Produces(MediaType.APPLICATION_JSON)
public Tournament getTournament(@PathParam("name") String uniqueName) {
return dao.get(uniqueName);
}
@Path("create")
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Tournament createTournament(Tournament tournament) {
return dao.create(tournament);
}
}
Si bien el DAO era un singleton, pero supongo que no habría mucha diferencia, solo en la primera línea:
private IEventSchedulerDao dao = EventSchedulerDao.getInstance();
Todavía tendría que usar una IEventSchedulerDao
instancia, pero supongo que todos los singletons funcionan así, ¿verdad? Por alguna razón, siempre correlaciono los singletons con los métodos estáticos, por lo que, en lugar de tener una instancia de singleton visible para el usuario getInstance()
, esto estaría oculto y él / ella simplemente usaría EventSchedulerDao.get(name)
, etc ... de manera estática. ¿Es esto una cosa o solo soy yo?
Entonces, ¿debería o no debería tener DAO singleton?
Y como pregunta adicional, ¿está bien que mi enfoque tenga puertas abiertas para que el usuario implemente sus propios DAO?
Respuestas:
No usaría un singleton. Es un antipatrón reconocido y dificulta las pruebas. Preferiría inyectar en una implementación concreta, y hacer que su servicio haga referencia a una interfaz DAO (que le permite inyectar diferentes implementaciones)
fuente
private IEventSchedulerDao dao = new EventSchedulerDao();
es donde te has equivocado. La implementación deIEventSchedulerDao
debe inyectarse a través del constructor y nunca cambiarse (es decir, deshacerse de élsetEventSchedulerDao
también).Un D ata A cceso O bject sólo debe existir realmente una vez en su aplicación. La lógica sigue siendo la misma, lo único que es diferente son los valores que entran y salen de los métodos que proporciona el DAO.
Con eso en mente, obviamente lo primero que suele suceder es implementar el DAO como un singleton fuerte , es decir, cuando tienes un
static
método en una clase de fábrica, algo así comogetInstance
cargar de forma diferida una instancia del DAO si es nulo y devolverlo.Disculpe si la sintaxis no es completamente correcta, no soy un programador de Java.
Esto es increíblemente difícil de probar, porque no se puede cambiar la implementación sin alterar el código de la
UsesDao
clase. Eso se puede hacer a través de algunos parches de mono , pero generalmente no se considera una buena práctica.Luego está la mejor manera, el patrón de singleton débil , donde no recuperas una instancia a través de un
static
método, sino que haces que todas las clases dependan de la instancia, ya sea a través de un constructor o un setter (en tuEventSchedulerService
estás usando la inyección setter).El único problema es que debe asegurarse de que todas las clases, que dependen de una instancia de clase que solo debería existir una vez que su ciclo de vida de la aplicación, estén tomando la misma instancia que su parámetro, es decir. el
new
se llama una sola vez en el objeto DAO en toda la aplicación.Obviamente, esto es increíblemente difícil de rastrear y construir el gráfico de objetos es un trabajo tedioso y molesto.
Afortunadamente, hay contenedores de IoC , que lo hacen mucho más fácil. Además de Spring , el contenedor Guice IoC de Google es bastante popular entre los programadores de Java.
Cuando se usa un contenedor IoC, lo configura para que se comporte de cierta manera, es decir. dirá si se supone que debe construir ciertas clases y si se requiere alguna clase como dependencia, cómo debe verse la dependencia (si siempre debe ser una nueva instancia o un singleton) y el contenedor lo conecta todo.
Puede consultar este enlace para ver un ejemplo singleton con Guice.
Pros y contras de usar un contenedor de IoC
Pros
Contras
fuente
Singleton se refiere al concepto solo una instancia y la forma de obtener acceso a la instancia (a través del método estático tan famoso getInstance () )
Pero todavía hay una instancia detrás de todo eso. Un objeto construido con una especie de acceso restringido.
En su caso, preferiría el enfoque DI (inyección de dependencia). Como el primer bloque de código que has expuesto. Solo un pequeño cambio. Inyecte el DAO a través del constructor. Para eliminar o no el setter depende de usted. Si desea proteger el controlador de los cambios en el tiempo de ejecución, elimínelo. Si desea ofrecer esa posibilidad, consérvela.
Tiene razón al usar una interfaz y ofrecer una ventana abierta para futuras implementaciones de DAO. Puede o no ser necesario. Solo toma un minuto más de trabajo, pero hace que su diseño sea flexible. Su memoria DAO es bastante común. Muy útil como simulacro en el momento de la prueba. O como implementación DAO predeterminada.
Solo una pista. Los recursos estáticos (objetos, métodos, constantes o variables) son como recursos globales. Si los globales son malos o no, es cuestión de necesidades o gustos. Sin embargo, hay defectos implícitos vinculados a ellos. Estos están relacionados con la concurrencia , la seguridad de subprocesos (en Java, no sé sobre otros idiomas), la serialización ...
Por lo tanto, sugeriría usar las estadísticas con cautela
fuente