Estou desenvolvendo uma API RESTful e acho conveniente usar DAOs para meus recursos porque, embora planeje apenas usar a memória para armazená-los, não quero fechar uma porta para quem estiver usando minha biblioteca, se eles decidirem usar uma implementação de banco de dados para o DAO.
Minha pergunta é se o DAO deve ser um singleton ou não. Caso contrário, o serviço terá uma instância do DAO e seria mais ou menos assim:
@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);
}
}
Embora o DAO fosse um singleton, mas acho que não haveria muita diferença, apenas na primeira linha:
private IEventSchedulerDao dao = EventSchedulerDao.getInstance();
Eu ainda teria que usar uma IEventSchedulerDao
instância, mas acho que todos os singletons funcionam assim, certo? Por alguma razão, eu sempre correlaciono singletons a métodos estáticos; portanto, em vez de ter uma instância singleton visível para o usuário getInstance()
, isso estaria oculto e ele / ela usaria EventSchedulerDao.get(name)
, etc ... de maneira estática. Isso é uma coisa ou sou apenas eu?
Então, devo ou não ter DAOs singleton?
E, como uma questão paralela, está bem minha abordagem ter portas abertas para o usuário implementar seus próprios DAOs?
Respostas:
Eu não usaria um singleton. É um anti-padrão reconhecido e dificulta o teste. Prefiro injetar uma implementação concreta e fazer com que seu serviço faça referência a uma interface DAO (permitindo que você injete implementações diferentes)
fonte
private IEventSchedulerDao dao = new EventSchedulerDao();
é onde você errou. A implementaçãoIEventSchedulerDao
deve ser injetada através do construtor e nunca alterada (isto é, livrar-sesetEventSchedulerDao
também).A D ata A cesso O bject realmente só deve existir uma vez na sua aplicação. A lógica permanece a mesma, as únicas coisas diferentes são os valores que entram e saem dos métodos fornecidos pelo DAO.
Com isso em mente, obviamente, a primeira coisa que normalmente acontece é implementar o DAO como um singleton forte , ou seja, quando você tem um
static
método em uma classe de fábrica, algo comogetInstance
, carregar preguiçosamente uma instância do DAO se ele for nulo e retorná-lo.Com licença, se a sintaxe não estiver totalmente correta, eu não sou um programador Java.
Isso é incrivelmente difícil de testar, porque você não pode trocar a implementação sem alterar o código da
UsesDao
classe. Isso pode ser feito através de alguns remendos de macacos , mas geralmente não é considerado uma boa prática.Depois, existe a melhor maneira, o padrão singleton fraco , em que você não recupera uma instância por meio de um
static
método, mas faz com que todas as classes dependam da instância por meio de um construtor ou de um setter (no seuEventSchedulerService
uso da injeção de setter).O único problema é que você precisa garantir que todas as classes, que dependem de uma instância da classe que só deve existir uma vez que o ciclo de vida do aplicativo, estejam executando a mesma instância que o parâmetro, por exemplo. o
new
é chamado apenas uma vez no objeto DAO em todo o aplicativo.Obviamente, isso é incrivelmente difícil de rastrear e construir o gráfico de objetos é um trabalho tedioso e irritante.
Felizmente, existem recipientes de IoC , o que facilita muito. Além de Spring , o contêiner Guice IoC do Google é bastante popular entre os programadores de Java.
Ao usar um contêiner de IoC, você o configura para se comportar de uma certa maneira, ou seja. você diz se como deve construir determinadas classes e se é necessária alguma classe como uma dependência, como a dependência deve parecer (se sempre deve ser uma nova instância ou um singleton) e o contêiner conecta tudo.
Você pode verificar este link para um exemplo único com o Guice.
Prós e contras do uso de um contêiner de IoC
Prós
Contras
fonte
Singleton está se referindo ao conceito apenas uma instância e a maneira de obter acesso à instância (por meio do famoso método estático getInstance () )
Mas ainda há um exemplo por trás de tudo isso. Um objeto construído com uma espécie de acesso restrito.
No seu caso, eu preferiria a abordagem DI (injeção de dependência). Como o primeiro bloco de código que você expôs. Apenas uma pequena mudança. Injete o DAO via construtor. Para remover ou não, a incubadora é sua. Se você deseja proteger o Controller contra alterações no tempo de execução, remova-o. Se você deseja oferecer essa possibilidade, mantenha-a.
Você está certo em usar uma interface e oferecer uma janela aberta para futuras implementações do DAO. Pode ou não ser necessário. Demora apenas mais um minuto de trabalho, mas torna seu design flexível. O seu DAO na memória é bastante comum. Muito útil como simulação no momento do teste. Ou como implementação padrão do DAO.
Apenas uma dica. Recursos estáticos (objetos, métodos, constantes ou variáveis) são como recursos globais. Se os globais são maus ou não, é uma questão de necessidades ou gostos. No entanto, existem deficiências implícitas ligadas a eles. Eles estão relacionados à simultaneidade , segurança de threads (em Java, não conhece outras linguagens), serialização ...
Então eu sugiro usar a estática com cautela
fonte