Solucionado (ver solução)
Solucionado
(ver solução)
4
respostas

Como instanciar a classe Banco uma única vez?

Uma coisa que me incomodou durante todo o projeto até aqui, no sentido de não parecer certo, foi que dentro de cada servlet, criamos uma instância nova da classe Banco para usá-la.

Não teria como instanciar a classe Banco uma única vez na aplicação e usar essa instância sempre que precisar?

4 respostas

Sim , têm, e você está falando de Singleton : uma classe-objeto capaz de ser instanciada(criada em memória pronta para seu uso) uma ÚNICA VEZ e com visibilidade e acessibilidade global dessa instância em um determinado escopo de projeto. Veja o link: https://www.devmedia.com.br/trabalhando-com-singleton-java/23632

Oi Thiago, obrigado pela resposta.

Eu ainda não cheguei na aula de padrões de projetos, mas pelo que eu li no artigo é isso mesmo que quero fazer.

Porém eu havia feito algo parecido e me deparei com a seguinte situação que gostaria de saber como contornar:

Declarei os métodos de classe (static). Ex.: Banco.getEmpresas(): List ou Banco.removeEmpresa(Integer id): void

Algumas vezes funcionou, mas me deparei muitas vezes com um erro de compilação dizendo que um método estático não pode ser acessado de um método não estático.

Em teoria eu sei que o método estático é de classe e o não-estático é de instância, por isso o compilador não aceita essa chamada, uma vez que ele não garante que haverá um objeto instanciado em tempo de execução para chamar o não estático. Me diz se estou errado, por favor.

Nesse caso qual seria a saída? Mudar a assinatura do método chamador para estático? Não acho que seria uma boa prática.

solução!

A ideia do Singleton é que a classe seja estática, mas os métodos não. Assim, toda vez que você precisar acessar algum serviço do banco, você utilize a classe que está em memória. Os métodos não serão estáticos e nem podem ser. Vou montar um exemplo bem básico abaixo para tomar como base, neste caso, para recuperar uma conexão de um DataSource:

public class DBFactory { public static DBFactory factory = null; private DataSource dataSource; public static DBFactory getInstance() { if (factory == null) factory = new DBFactory(); return factory; } private DBFactory(){ try { Context initCtx = new InitialContext(); Context envCtx = (Context) initCtx.lookup("java:comp/env"); dataSource = (DataSource) envCtx.lookup("jdbc/dataSource"); } catch (Exception e) { Util.logError(e); } } public Connection getConnection() throws Exception{ try { return dataSource.getConnection(); } catch (Exception e) { Util.logError(e); throw e; } } }

Criei uma variável factory do tipo DBFactory (nome da classe), esta estática. Assim, essa variável será a que ficará em memória. Quando alguma outra classe precisa dela, chamará o método getInstance(), que retorna um DBFactory . Note que no getInstance(), caso esteja nula minha variável, ela cria uma instância da classe, e no meu método construtor, eu faço o acesso ao datasource. Assim, toda vez que alguma classe precisar de uma conexão, meu Datasource sempre estará disponível, e a minha instância em memória só retorna uma conexão. Na minha implementação, só acesso uma vez o datasource, em quem precisar requisita uma conexão.

Oi Thiago, muito obrigado pela resposta. Ficou bem mais claro agora. Dei uma refatorada na sua resposta acima para ficar mais claro para outros leitores.

Abs

A ideia do Singleton é que a classe seja estática, mas os métodos não. Assim, toda vez que você precisar acessar algum serviço do banco, você utilize a classe que está em memória. Os métodos não serão estáticos e nem podem ser. Vou montar um exemplo bem básico abaixo para tomar como base, neste caso, para recuperar uma conexão de um DataSource:

public class DBFactory {

    public static DBFactory factory = null;
    private DataSource dataSource;

    public static DBFactory getInstance() {
        if (factory == null)
            factory = new DBFactory();
        return factory;
    }

    private DBFactory() {
        try {
            Context initCtx = new InitialContext();
            Context envCtx = (Context) initCtx.lookup("java:comp/env");
            dataSource = (DataSource) envCtx.lookup("jdbc/dataSource");
        } catch (Exception e) {
            Util.logError(e);
        }
    }

    public Connection getConnection() throws Exception {
        try {
            return (Connection) dataSource.getConnection();
        } catch (Exception e) {
            Util.logError(e);
            throw e;
        }
    }
}

Criei uma variável factory do tipo DBFactory (nome da classe), esta estática. Assim, essa variável será a que ficará em memória. Quando alguma outra classe precisa dela, chamará o método getInstance(), que retorna um DBFactory . Note que no getInstance(), caso esteja nula minha variável, ela cria uma instância da classe, e no meu método construtor, eu faço o acesso ao datasource. Assim, toda vez que alguma classe precisar de uma conexão, meu Datasource sempre estará disponível, e a minha instância em memória só retorna uma conexão. Na minha implementação, só acesso uma vez o datasource, em quem precisar requisita uma conexão.