Dúvida sobre implementação do padrão de projeto SINGLETON

7 respostas
M

Pessoal,

Em primeiro lugar, peço desculpa as moderadores se este não for o local mais adequado para postar esta dúvida. Procurei no GUJ uma sala específica sobre Padrões de
Projeto mas não achei, daí resolvi postar minha dúvida aqui em Java Avançado. Portanto, sintam-se à vontade para mover o tópico para o lugar que acharem mais adequado.
Segue, abaixo, o código de uma classe de conexão, onde estou tentando fazer uma implementação do padrão de projeto SINGLETON, de modo que eu tenha apenas uma
conexão ativa com o banco de dados. A classe está funcionando, ou seja, ela gera a conexão. Como ainda estou aprendendo a mexer com padrões de projeto estou em dúvida se a implementação do SINGLETON está correta no código abaixo :

/*

  • FabricaDeConexoes.java

*/

package persistencia;

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.SQLException;

import javax.swing.JOptionPane;

/**
*

  • @author Max Carvalho
    */

public class FabricaDeConexoes {

// declaração de atribudos 
private static Connection conn;
private String driver;
private String url;
private String username;
private String password;

// construtor

FabricaDeConexoes() {
     
    // inicializa atributos privados
    driver = "com.mysql.jdbc.Driver";
    url = "jdbc:mysql://127.0.0.1:3306/<nome_do_banco>";
    username = "<usuario>";
    password = "<senha>"; 
    conn = null;
    
    //invoca método obtemConexao()
    obtemConexao();
    
}

/* inicio metodo obtemConexao() */
private Connection obtemConexao() {
    
    try { // inicio bloco try-catch
    
        // carrega e registra o driver
        Class.forName(driver);
        
        // obtem uma instancia de conexao
        if ( conn == null ) {  // padrao de projeto SINGLETON
            
            conn = DriverManager.getConnection(url, username, password);
            
        }
    
        return conn;
        
    } catch (ClassNotFoundException cnfex) {
        
        System.err.println("Classe do driver não encontrada. Impossível carregar o driver");
        cnfex.printStackTrace();
        conn = null;
        return conn;
                   
    } catch (SQLException sqlex) {
        
        System.err.println( "Impossivel conectar" );
        sqlex.printStackTrace();
        conn = null;
        return conn;
          
    }
    // fim bloco try-catch
    
}
/* fim metodo obtemConexao */

} // fim clase FabricaDeConexoes


Então as dúvidas são :

1a - A tentativa de implementação do padrão de projeto SINGLETON nesta classe está correta ?

2a - Eu posso usar apenas a condição booleana para verificar se há uma oura conexão ativa ou tenho que usar em algum lugar o método “instance of” ?

3a - Vocês conseguem enxergar alguma outra coisa que possa ser melhorada nesta classe ?

Agradeço qualquer ajuda que me for enviada.

Max Carvalho

7 Respostas

W

Eu faria o metodo obtemConexao static ai vc usaria assim, por exemplo:

Connection con = FabricaDeConexoes.getConnection();

Outra coisa, nada demais…

} catch (ClassNotFoundException cnfex) {

System.err.println("Classe do driver não encontrada. Impossível carregar o driver");
cnfex.printStackTrace();

} catch (SQLException sqlex) {

System.err.println( "Impossivel conectar" );
sqlex.printStackTrace();

} finally {

conn = null;
return conn;

}
M

Está errado…

Vc deve usar variavel e metodos estáticos.

Faça assim…!!!

private static FabricaDeConexoes instance; // variável deve ser static.

private FabricaDeConexoes (){} // deve ser privado o construtor.

// este metod que vc pegará a referência do objeto.
public FabricaDeConexoes getInstance(){

if(instance == null){
       instance = new FabricaDeConexoes ();
   }

   return instance;

}

// é só isso.

flw

Giulliano

Muito bom o seu interesse em padrões de projeto…

A aplicação do singleton (que já foi abolida em muitos casos) esta correta. Agora o contexto que você utilizou para aplica-la esta errado.

Conexões não devem depender de um Singleton, recomendo um pool de conexões. Se a sua dúvida for com relação a obter uma melhor prática de como gerar conecções estude o padrão factory.

ouitra coisa comece a usar as tags, pra facilitar…

package persistencia; 

import java.sql.Connection; 
import java.sql.DriverManager; 
import java.sql.SQLException; 
import javax.swing.JOptionPane; 

/** 
* 
* @author Max Carvalho 
*/ 

public class FabricaDeConexoes { 

// declaração de atribudos 
private static Connection conn; 
private String driver; 
private String url; 
private String username; 
private String password; 

// construtor 

FabricaDeConexoes() { 

// inicializa atributos privados 
driver = "com.mysql.jdbc.Driver"; 
url = "jdbc:mysql://127.0.0.1:3306/&lt;nome_do_banco&gt;"; 
username = "&lt;usuario&gt;"; 
password = "&lt;senha&gt;"; 
conn = null; 

//invoca método obtemConexao() 
obtemConexao(); 

} 

/* inicio metodo obtemConexao() */ 
private Connection obtemConexao() { 

try { // inicio bloco try-catch 

// carrega e registra o driver 
Class.forName(driver); 

// obtem uma instancia de conexao 
if ( conn == null ) { // padrao de projeto SINGLETON 

conn = DriverManager.getConnection(url, username, password); 

} 

return conn; 

} catch (ClassNotFoundException cnfex) { 

System.err.println("Classe do driver não encontrada. Impossível carregar o driver"); 
cnfex.printStackTrace(); 
conn = null; 
return conn; 

} catch (SQLException sqlex) { 

System.err.println( "Impossivel conectar" ); 
sqlex.printStackTrace(); 
conn = null; 
return conn; 

} 
// fim bloco try-catch 

} 
/* fim metodo obtemConexao */ 

} // fim clase FabricaDeConexoes
victorwss

Na minha opinião, o único uso justificável de singletons seria para classes imutáveis ou sem estado onde não haja motivo para existir mais de uma instância. Exemplo: Servlets bem projetados (o container só cria uma instância por classe). Contra-exemplo: Algo que encapsule a conexão com o BD, pois há coisas que podem precisar de mais de uma conexão, ou que funcionam melhor com mais de uma conexão. Há aplicações que usam mais de um BD ao mesmo tempo e se a conexão for corrompida ou fechada, restaurá-la é muito mais trabalhoso do que criar uma nova.

Eu já sofri por causa do singleton. Em um projeto que trabalhei, a conexão como BD era singleton, até o dia que precisavamos ter duas Threads acessando o BD concorrentemente sem que uma interferisse na outra. Resultado: tivemos que refatorar a aplicação inteira.

Mais tarde um outro cara cometeu o mesmo erro e fez o usuário logado ser um singleton. Até que um dia chegou uma funcionalidade de troca de usuário com usuários em espera.

thiagopri

Concordo com o Giulliano,

Sempre que possível, conexões devem ser gerenciadas pelo container, através de Pool’s. Isso vai te dar muito mais performance e escalabilidade (uma vez que fica muito simples controlar o n. de conexoes no pool, conexões em idle, etc …). Uma dica é utilizar o Spring ou o Padrão COMMAND para gerenciar os recursos no Pool, ou seja, devolve-los quando não forem mais utilizados.

O padrão DAO (utilizando Factory) é realmente lindo de ver, porém, na minha humilde opnião, é uma basuca para matar barata. A não ser que esteja desenvolvendo um SW de prateleira, ou seja, não sabe qual será a infra (BD) do comprador, não vejo muito sentido em sua aplicação. MAS ISSO É UMA OPNIÃO PESSOAL.

victorwss

thiagopri:
Concordo com o Giulliano,

Sempre que possível, conexões devem ser gerenciadas pelo container, através de Pool’s. Isso vai te dar muito mais performance e escalabilidade (uma vez que fica muito simples controlar o n. de conexoes no pool, conexões em idle, etc …). Uma dica é utilizar o Spring ou o Padrão COMMAND para gerenciar os recursos no Pool, ou seja, devolve-los quando não forem mais utilizados.

O padrão DAO (utilizando Factory) é realmente lindo de ver, porém, na minha humilde opnião, é uma basuca para matar barata. A não ser que esteja desenvolvendo um SW de prateleira, ou seja, não sabe qual será a infra (BD) do comprador, não vejo muito sentido em sua aplicação. MAS ISSO É UMA OPNIÃO PESSOAL.

Na verdade só uma vez eu vi alguém usando o verdadeiro padrão DAO e retirando dele todos os reais benefícios que ele trás. Nas outras vezes, o que vi, foi uma versão distorcida dele, implementado por pessoas que não o entenderam direito e só recebem parcialmente os benefícios dele, criando alguns outros problemas também. Inclusive em livros é muito comum se ver implementações ruins de DAOs.

M

Obrigado a todos pelas explicações. Quanto à aplicação, é desktop mesmo, transacional, acessando um sgbd objeto-relacional, Oracle 10g.
[]'s
Max

Criado 21 de novembro de 2008
Ultima resposta 24 de nov. de 2008
Respostas 7
Participantes 6