Retornar ResultSet na classe abstrata

30 respostas
xdraculax

Pessoal, estou com o seguinte problema:

As classes de persistência de um projeto que estou trabalhando é em JDBC (não pode ser hibernate, por questões de desempenho).

Bem, nessas classes de persistência existem muitas operações com a mesma estrutura, como, por exemplo executar um Statement e retornar um ResultSet. Não faria sentido colocar o mesmo código repetido por todas as classes de persistência, portanto, coloquei o seguinte código na classe abstrata (AbstractePersistence):

protected ResultSet executarQueryToResultSet(String query){
		
		Statement statement = null;
		ResultSet resultSet = null;
		conexao = getConnection();
		
		try{

			statement = conexao.createStatement();
			resultSet = statement.executeQuery(query);
			conexao.commit();
			
		}catch(Exception ex){
			try { conexao.rollback(); } catch (SQLException e) { e.printStackTrace(); }
		}
		finally{
			liberarConexao(conexao);
			liberarStatment(statement);
		}
		return resultSet;
	}

Dessa forma eu não preciso toda vez que chamar um método em uma classe de persistência escrever o mesmo código repetitivo acima. Quando uma sub-classe quiser executar um ResultSet, é só chamar o método da super-classe e pronto.

O problema é: como o método retorna um ResultSet, e no mesmo método da classe abstrata, eu fecho a conexão (usamos um pool, portanto é obrigatório fechar a conexão, caso contrário o pool estoura), fechando a conexão, quem recebeu o ResultSet como retorno do método não vai conseguir obter os dados do ResultSet, pois o mesmo foi fechado.

Gostaria de saber a opnião de voces sobre estas decisões, e se tem algo melhor a ser feito. Pois dessa forma não está dando certo. :|

30 Respostas

P

Ao invés de retornar o ResultSet, retorne outro objeto. Por exemplo um array de Object:

ResultSet rs = ps.executeQuery(); if (rs.next()) { int colunas = rs.getMetaData().getColumnCount(); Object[] linha = new Object[colunas]; for (int i = 0; i < colunas; i++) { linha[i] = rs.getObject(i + 1); } return linha; }

B

Em outras palavras, ninguém da empresa sabe usar Hibernate, certo?

edmarr

Tente PrepareStatement

http://java.sun.com/docs/books/tutorial/jdbc/basics/prepared.html

Em outras palavras, ninguém da empresa sabe usar Hibernate, certo?

Bom tem que ver realmente , pois para se usar hibernate a modelagem do banco tem que estar bem definida , senao nosso amigo hibernate vai ficar
maluco maluco .

Retorne uma Coleção .

xdraculax

Não… em outras palavras usamos Hibernate “até dar uma dor” no sistema da central de processamento onde desempenho não é um requisito crítico.
Já no equipamento de campo onde recursos como memória e processamento são bem reduzidos, não usamos Hibernate, e sim JDBC.
Não podemos se dar ao luxo de ficar escrevendo nada em HSQL para ser traduzido para linguagem do banco (um over desnecessário).
Alem do +, não se tem pretenção de mudar o banco (Postgre) tão cedo, tão cedo mesmo.
Alem do +, se for pra usar o Hibernate executando query nativa, pra que usar Hibernate?

Se não tem nada de útil pra falar é melhor ficar calado.

xdraculax

pozzo:
Ao invés de retornar o ResultSet, retorne outro objeto. Por exemplo um array de Object:

ResultSet rs = ps.executeQuery(); if (rs.next()) { int colunas = rs.getMetaData().getColumnCount(); Object[] linha = new Object[colunas]; for (int i = 0; i < colunas; i++) { linha[i] = rs.getObject(i + 1); } return linha; }

Huunn, é uma boa idéia, gostei da sua abordagem :slight_smile:

Cara, eu acho que não resolveria meu problema. Se eu usa-se o PS, ainda teria de retornar um ResultSet vindo de minda classe abstrata ok?

xdraculax

Ae pessoal, lendo sobre algumas outras implementações da interface ResultSet, descobri que o JDBC também implementa conceitos de acesso a dados desconectados.

A classe CachedRowSetImpl é uma especialização da classe ResultSet que não usa ponteiro para os dados, e sim armazena-os em memória.
Assim, eu poderia retornar um objeto CachedRowSetImpl no retorno do método da classe abstrata.

Isso resolveria meu problema parcialmente, porque eu ainda teria problemas de consumo de recursos (se o colega fizer um select que retorne muitos resultados).

O que adotamos por enquanto foi:

As sub-classes liberam a conexão e result set’s e statements… quando achar uma solução melhor eu posto (ou se alguém souber e postar é bom também :)).

B

Performance? Ok.

  • Não é necessário fazer commits ou rollbacks em operações somente de leitura, como em consultas.
  • Se você fechar ou fizer qualquer operação num Statament, o ResultSet dele irá fechar.
  • Abrir e fechar conexões a cada método de consulta vai matar o teu banco de dados.
  • Commits devem ser realizados somente quando a execução das classes do domínio finalizar. Você irá acabar com dados inconsistentes no banco se não fizer isto.
ViniGodoy

Para resolver esse problema, procure sobre pools de conexões, como o DBCP ou o C3P0. Mas para a sua aplicação, mantenha essa política de que ela deve trabalhar “desconectada” e não “conectada”. O momento exato da desconexão física, deixe que um desses pools decida por você.

Dê uma olhada no Spring. Ele é muito parecido com o JDBC e já implementa suporte a tudo isso. E trabalha de maneira muito similar ao CachedRowSetImpl.

Ele também suporta batchUpdates e transações, transações aninhadas e stored procedures.

xdraculax

É, eu possi tirar isso dali. Não vai fazer diferença.

É exatamente esse o problema. Eu não posso liberar o statement na classe abstrata porque quando a sub-classe receber o resultado na verdade vai ter um ResultSet vázio (fechado).

O método getConnection() não cria conexão, ele vai pegar no pool (c3p0 - muito bom por sinal).

Não pensei nissi ainda…

Vini… vou dar uma olhada no Spring para ver como ele faz isso…

sergiotaborda
xdraculax:
Pessoal, estou com o seguinte problema:

As classes de persistência de um projeto que estou trabalhando é em JDBC (não pode ser hibernate, por questões de desempenho).

Bem, nessas classes de persistência existem muitas operações com a mesma estrutura, como, por exemplo executar um Statement e retornar um ResultSet. Não faria sentido colocar o mesmo código repetido por todas as classes de persistência, portanto, coloquei o seguinte código na classe abstrata (AbstractePersistence):

protected ResultSet executarQueryToResultSet(String query){
		
		Statement statement = null;
		ResultSet resultSet = null;
		conexao = getConnection();
		
		try{

			statement = conexao.createStatement();
			resultSet = statement.executeQuery(query);
			conexao.commit();
			
		}catch(Exception ex){
			try { conexao.rollback(); } catch (SQLException e) { e.printStackTrace(); }
		}
		finally{
			liberarConexao(conexao);
			liberarStatment(statement);
		}
		return resultSet;
	}

Dessa forma eu não preciso toda vez que chamar um método em uma classe de persistência escrever o mesmo código repetitivo acima. Quando uma sub-classe quiser executar um ResultSet, é só chamar o método da super-classe e pronto.

só existe um problema com esse método : é POG.

Esse método mostra que a sua equipe não sabe trabalhar com JDBC. Então não fique ofendido quando desconfiamos que não saiba usar o hibernate.
E quando digo "usar" quero dizer "entender e fazer uso de features avançadas".

Simplesmente descarte esse método. Refactore seu codigo. É uma péssima ideia.

1) Use PreparedStatement SEMPRE
2) Abra e feche a conexão ao mesmo tempo que abre e fecha a transação. O Pool de conexão é inutil se vc não tem conceito de transação.
3) Monte o PreparedStatement , execute e leia o ResultSet num unico método. Não delegue esse tipo de controle.
4) Sempre feche os statements ao mesmo tempo que o resultSet.
5) menipule SQLException corretamente ( nada de e.printStackStrace)

só existe um motivo para não fechar o resultset e o retornar para ser usado depois: o padrão Fastlane Reader. Não é o seu caso.

Remodele seu codigo e terá menos problemas.

xdraculax

Porque?
Eles são compilados para ficarem no cache do banco, mas não vi deferenças em testes que fiz com um Statement.
Você fez testes de desempenho? Ou só leu que sempre deve-se usar PreparedStatement?

Transações são comitadas ao retornarem para o pool (quando é dado um close() na conexão) de qualquer jeito.

Não quero fazer isso. Não vejo vantagem nenhuma nessa sua abordagem.

Isso já está sendo feito pelos métodos de liberar, você não viu?

Meu foco não é esse, depois que resolver o meu problema, ai sim vou fazer o trabalho mecânico de tratar a exception e logar.

POG?

Então quer dizer que se eu quero executar um Statement em vários locais de minhas classes de persistência, eu replico o mesmo código, com a mesma estrutura de try…cath rs.close stm.close… em todos, da mesma forma; e colocar isso na classe abstrata onde todas as sub-classes executam o mesmo método da super-classe é POG?

Diga o que você faria então.

B

Acho que o pior problema desse método é que um cliente pode mandar uma String para ele e ferrar completamente com a base de dados da tua aplicação, ou derrubar o banco de dados inteiro. Procure saber sobre SQL Injection, e como o PreparedStatement ajuda a evitá-lo.

Faça os DAOs da tua aplicação retornarem somente o objeto ou uma coleção de objetos pesquisados, esses objetos sendo feitos a partir das classes do domínio da tua própria aplicação.

Exemplo de interfaces de métodos da classe de acesso ao banco:

public List<Cliente> buscarClientesPorNome(String nome)

public List<Cliente> buscarClientesPorExemplo(Cliente cliente)

Statements e ResultSets devem ficar encapsulados somente dentro do próprio método, nunca saindo para fora. Para fugir a essa regra, você tem que ter um bom motivo e 10x mais de cuidado ao deixar os teus objetos da camada de persistência fujam para outra camada.

sergiotaborda

Porque?
Eles são compilados para ficarem no cache do banco, mas não vi deferenças em testes que fiz com um Statement.
Você fez testes de desempenho? Ou só leu que sempre deve-se usar PreparedStatement?

Não é um problema de performance. É um problema de segurança. Ele ajuda a evitar SQLInjection

Se isso é verdade vc não está usando o conceito de transação. Transação necessita de um commit ou roolbak explicito.
Se vc deixa para comitar no close ( o que na realidade nunca acontece, ou se dá no commit ou se dá no execute se o autocommit está ligado) isso signfica que vc deve estar usando autocomit que é exatamente a antitese do conceito de transação.

Se vc não quer faze isso, então não se queixe que tem problemas.
Existe uma máxima que diz :"Não ha ‘eu’ em “arquitetura” (There is no I in architecture)
O que significa que o vc quer ou não quer é irrelevante.

sim.


Diga o que você faria então.

Já lhe disse o que faria.
Colocar métodos genéricos em classes abstratas parece legal, mas precisa aprender quando parar. Este é um caso em que deve parar de fazer isso.

xdraculax

Sim é POG? Explique porque ou isso é um “EU acho que é POG”?
Não é POG, é divergência de opnião. E você não tem uma justificativa plausível, portanto, sem comentários.
Pra mim, repetir a mesma estrutura de código por n métodos de classes de persistência é que é POG. E foi o que você disse que faria.

Quanto a segurança, eu até entendo isso; mas quem vai escrever os SQL são programadores, e não “paes & mães”.
O sistema não tem entradas inseridas por usuários, tudo é gerado por um Hardware. Então esse conceito de segurança, neste contexto, não faz sentido.
Se o programador é burro pra escrever um SQL desastroso, ele vai fazer isso em qualquer outra situação.

Você simplesmente leu que deve-se usar PS em todas as situações e acreditou. Nem se ocupou em fazer testes para ver se realmente faz sentido utilizá-lo em todas as situações.

Com relação a dar um commit no retorno da conexão para o pool realmente concordo com você. Não é muito inteligente.

ViniGodoy

Sugiro fortemente que você veja a implementação disso aí no Spring. Você vai se surpreender.

mario.fts

xdraculax:
Sim é POG? Explique porque ou isso é um “EU acho que é POG”?
Não é POG, é divergência de opnião. E você não tem uma justificativa plausível, portanto, sem comentários.
Pra mim, repetir a mesma estrutura de código por n métodos de classes de persistência é que é POG. E foi o que você disse que faria.

Quanto a segurança, eu até entendo isso; mas quem vai escrever os SQL são programadores, e não “paes & mães”.
O sistema não tem entradas inseridas por usuários, tudo é gerado por um Hardware. Então esse conceito de segurança, neste contexto, não faz sentido.
Se o programador é burro pra escrever um SQL desastroso, ele vai fazer isso em qualquer outra situação.

Você simplesmente leu que deve-se usar PS em todas as situações e acreditou. Nem se ocupou em fazer testes para ver se realmente faz sentido utilizá-lo em todas as situações.

minha humilde opnião? sim, é pog. Tanto é pog, que está gerando um problema pra vc, que não existiria se estivesse sendo utilizado corretamente.

conexões, statments, e resultsets são recursos de IO. vc abre, vc fecha. vc só tem que determinar em que ponto vc vai fazer isso, e essa regra tem que valer pra todo o sistema. não tem como fugir dessa estrutura quando se está trabalhando com jdbc:

Connection conn = null; //... o que mais vc quiser, statmente, resultset geralemnte try{ pega uma conexão monta o statment cria o resultset itera e faz o q vc quiser }catch(SQLException e){ trata } finally{ fecha os recursos }

o código pra fechar os recursos é um porre? é mesmo. mas basta criar métodos pra fechar esses recursos, como existe no DBUtils da apache.(close e closeQuietly, ver aqui).

o PreparedStatment não é só amis seguro, evitando sqlinjection,ele tbm é mais rápido, se vc for rodar aquiele comando mais de uma vez. e ainda reduz os problemas de ficar montando o sql com concatenações de strings, tipo problemas de aspas por exemplo.

ViniGodoy

Quem acha que não tem como fugir dessa estrutura, veja o Spring.
E realmente é pog manter essa estrutura em todo lugar, eu concordo com o xdraculax. Embora ele realmente devesse usar o PreparedStatement, é realmente louvável a preocupação em não repetir código. Repetição de código é uma idiotice, um dos grandes males a serem evitados.

xdraculax

Já vi o DBUtils da apche.
Mas como já tinhamos feito os métodos para liberar conexão, statements … Não usei o DBUtils.

O que você falou é verdade, recursos IO devem ser abertos, utilizados e liberados; o que impede que isso seja feito na classe abstrata?
Só serve se for no método que você está vendo na sub-classe?

Repetir código é matar a Orientação a Objetos, piora manutenção, principalmente quando se usa os try… cath como “muleta de desenvolvimento”.

Infelizmente não dá certo porque o modelo de leitura do ResultSet é conectado. Mas isso já resolvi usando outra implementação da interface.

Como eu disse, a segurança do PS nesse caso não é relevante pois o sistema não tem entradas de dados inseridas por usuários. Todos os dados são gerados por hardware.

O desempenho, bem, todo livro e documentação diz que é melhor, mas no frigir dos ovos, não vejo isso.

Não costumo acreditar nos rótulos, prefiro testar é ver se realmente é a “Coca-Cola toda”.

Mas tudo bem, se todo mundo acha que é gambiarra, fazer o que.
Eu vou continuar fazendo assim, pois acredito que não é POG. Mesmo assim, obrigado.

mario.fts

ViniGodoy:
Quem acha que não tem como fugir dessa estrutura, veja o Spring.
E realmente é pog manter essa estrutura em todo lugar, eu concordo com o xdraculax. Embora ele realmente devesse usar o PreparedStatement, é realmente louvável a preocupação em não repetir código. Repetição de código é uma idiotice, um dos grandes males a serem evitados.

Sinceramente eu não vi, não posso falar. Vc ta se referindo ao código que controla o JdbcTemplate?

não gosto de repetir código tbm, mas neste caso em especifico eu não conheço outra alternativa. Espero mudar conhecendo essa abordagem do spring.

xdraculax

Pois é, vou acabar usando pela “limpesa” no código; e também pelo fato de que concatenar String´s no Java é um problema de criação de novos objetos desperdíçando memória.

Pois é :), isso é realmente um problema.

mario.fts
public abstract class JdbcSupport{
	
	 protected Object executarQuery(String query){  
		       
		     Statement statement = null;  
		    ResultSet resultSet = null;  
		     conexao = getConnection();
		     Object retorno = null
		       
		     try{  
		   
		         statement = conexao.createStatement();  
		         resultSet = statement.executeQuery(query);  
		         conexao.commit();  
		           
		         retorno = resultSetToModel(resultSet);  
		     }catch(Exception ex){  
		         try { conexao.rollback(); } catch (SQLException e) { e.printStackTrace(); }  
		     }  
		     finally{  
		         liberarConexao(conexao);  
		         liberarStatment(statement);  
		     }
		     
		     return retorno;
		 } 
	 
	 public abstract Object resultSetToModel(ResultSet rs);
	
}

public class JdbcSupportModel extends JdbcSupport{
	
	public Object resultSetToModel(ResultSet rs){
		//aqui vc transforma esse resultset no seu objeto de modelo
	}
	
}

lógico que retornar object é ruim, mas é apenas uma idéia. assim vc não precisa ficar repetindo o código.

xdraculax

Sim concordo que retornar object não é muito legal.

Mas o seu método resultSetToModel pode ser abstrato ou genérico, assim a sub-classe retornaria a lista de entidades no qual ela representa.
Mas essa não é a questão.

Como já tinham falado anteriormente, essa é uma boa idéia, e estou pensando se é possível colocá-la no código.

sergiotaborda

ViniGodoy:
Quem acha que não tem como fugir dessa estrutura, veja o Spring.
E realmente é pog manter essa estrutura em todo lugar, eu concordo com o xdraculax. Embora ele realmente devesse usar o PreparedStatement, é realmente louvável a preocupação em não repetir código. Repetição de código é uma idiotice, um dos grandes males a serem evitados.

Humm… tlv não estejamos falando do mesmo Spring. O que o Spring faz é exactamente o que o mario.fts falou. Esse padrão de tratamento é universal e a razão da sua existência é uma coisa chamada ACID

O codigo fonte está aqui

E o codigo é este:

public Object   execute(StatementCallback action) throws DataAccessException {
         Assert.notNull(action, "Callback object must not be null");

          Connection   con = DataSourceUtils.getConnection(getDataSource());
         Statement   stmt = null;
         try {
             Connection   conToUse = con;
             if (this.nativeJdbcExtractor != null &&
                     this.nativeJdbcExtractor.isNativeConnectionNecessaryForNativeStatements()) {
                 conToUse = this.nativeJdbcExtractor.getNativeConnection(con);
             }
             stmt = conToUse.createStatement();
             applyStatementSettings(stmt);
             Statement   stmtToUse = stmt;
            if (this.nativeJdbcExtractor != null) {
                 stmtToUse = this.nativeJdbcExtractor.getNativeStatement(stmt);
             }
             Object   result = action.doInStatement(stmtToUse);
             handleWarnings(stmt.getWarnings());
             return result;
         }
         catch (SQLException   ex) {
             // Release Connection early, to avoid potential connection pool deadlock
 // in the case when the exception translator hasn't been initialized yet.
 JdbcUtils.closeStatement(stmt);
             stmt = null;
             DataSourceUtils.releaseConnection(con, getDataSource());
             con = null;
             throw getExceptionTranslator().translate("StatementCallback", getSql(action), ex);
         }
         finally {
             JdbcUtils.closeStatement(stmt);
            DataSourceUtils.releaseConnection(con, getDataSource());
        }
     }

O reaproveitamento e a abstração é conseguida pelo uso de classes utilitárias, callbacks e proxys. Tudo com exceções devidamente tratadas.
É tecnologia que permite que em apenas um método e com a estrutura clássica, muita coisas possa ser feita.

Já agora é interessante dar uma olhada no método query.

O ponto não é que não devemos consolidar tudo num método. O ponto é que existem formas certas e formas erradas de consolidar as coisas num método.
Para quem não gosta de pensar em certo e errado: existem formas acopladas e formas desacopladas de consolidar e abstrair.

ViniGodoy

Então Sérgio. Esse código é exatamente o que o xdraculax estava propondo no início, embora o design dele ainda esteja muito atrás do design do spring, por desconhecimento do JDBC (como vc mesmo citou).

E o método faz exatamente o que você disse para ele não fazer, concentra todo tratamento num lugar só, evitando toda a repetição enfadonha que o JDBC impõe. Talvez você tenha se expressado mal, mas eu entendi que você falou que isso era POG, e que ele deveria reproduzir todo esse código de tratamento várias vezes. E foi isso que deixou o xdraculax de cabelo em pé.

Para um método ainda mais parecido com o que ele fez, veja a implementação do queryForRowSet.

Ok, como contra argumento você vai dizer que o Spring usa as abstrações certas. Entretanto, não dá para negar que o colega estava no caminho certo, e que essa abstração iria surgir cedo ou tarde, a medida que ele necessitasse de recursos mais avançados, como transações. Tanto que, ele mesmo já estava no caminho de copiar as respostas para um novo objeto, como o próprio Spring faz.

sergiotaborda

ViniGodoy:
Então Sérgio. Esse código é exatamente o que o xdraculax estava propondo no início, embora o design dele ainda esteja muito atrás do design do spring, por desconhecimento do JDBC (como vc mesmo citou).

E o método faz exatamente o que você disse para ele não fazer, concentra todo tratamento num lugar só, evitando toda a repetição enfadonha que o JDBC impõe. Talvez você tenha se expressado mal, mas eu entendi que você falou que isso era POG, e que ele deveria reproduzir todo esse código de tratamento várias vezes. E foi isso que deixou o xdraculax de cabelo em pé.

Para um método ainda mais parecido com o que ele fez, veja a implementação do queryForRowSet.

Ok, como contra argumento você vai dizer que o Spring usa as abstrações certas. Entretanto, não dá para negar que o colega estava no caminho certo, e que essa abstração iria surgir cedo ou tarde, a medida que ele necessitasse de recursos mais avançados, como transações. Tanto que, ele mesmo já estava no caminho de copiar as respostas para um novo objeto, como o próprio Spring faz.

O que eu disse foi

“esse método” se refere ao método que foi apresentado. Eu não disse “esse conceito” , nem “essa ideia” , nem "qualquer tipo de método que encapsule o tratamento de statements"
Acho que a diferença é obvia e ha uma mal intrepretação vossa.

A minha objeção principal é colocar o método numa classe abstrata em vez de numa classe especializada. Essa é a principal POG aqui, por achar que colocando em classes abstrata e herdando dela estaria reaproveitando codigo. Não. Reaproveitamento acontece criando classes especificas e chamando-as. Que é o que o Spring faz, o Hibernate e o MiddleHeaven :wink:
Repare que o JDBCTemplate é usado por outras classes para executar sql, ele não é herdado.

Tb não referi nada em relação “ao caminho certo” em que ele estaria. Apenas no caminho errado que ele precorreu: o conceito de usar métodos em classes abstratas para reaproveitar codigo.

xdraculax

Colocar o método na classe abstrata e chamá-lo nas especializações é exatamente o que eu faço, não há absolutamente nada de errado nisso. É exatamente o que o Spring faz pelo que estou vendo, e isso não é nenhuma novidade.

Quanto ao tratamento de exceções, não tem nada a ver o que o sergio falou. A questão abordada aqui não era o tratamento de exceções, e sim o problema com o ResultSet.
Sabe aqueles exemplos de livros que querem mostrar a declaração de uma variável e colocam 400 linhas de código para tal? Pois é… não era essa minha intenção; meu foco era o problema de chamada do método e liberação dos recursos IO.

Gostei do códgo do Spring. Lógico, meu código está pobre ainda, comecei a implantar esse conceito agora, por ver o problema de repetição de código, ainda tenho que amadurecê-lo muito.

Infelizmente ainda não consigo desenhar um sistema e codificá-lo de uma vez e nunca ter que melhorar uma linha de código.

Bem, uso classes abstratas para o que elas foram feitas: representar abstrações. Abstrações reutilizáveis entre as implementações, por consequência: reuso de código.

E sim, o sergio disse que reutilizar a mesma estrutura de códgo na classe abstrata era POG (primeira página, msg 14).

sergiotaborda

xdraculax:
Colocar o método na classe abstrata e chamá-lo nas especializações é exatamente o que eu faço, não há absolutamente nada de errado nisso. É exatamente o que o Spring faz pelo que estou vendo, e isso não é nenhuma novidade.

Não. Veja com mais atenção. O método do spring é publico e a classe não é abstrata nem é feita para ser herdada.

É exactamente esse conceito que estou dizendo que está errado. Vc está equivocadamente associando “abstração” com “classe abstrata”. Não é assim que OO funciona.
Uma “abstração” é a identificação de um conceito ou mecanismo que pode ser tratado como uma unidade em si mesmo. Por exemplo, Cliente é uma abstração. usuário é uma abstração. Contudo, as classes que os representam não são abstratas.

Reuso de codigo não é conseguido via herança. É isso que estou lhe dizendo. Vc usa herança para categorizar (organizar) as ideias, não para reaproveitar codigo.

A palavra chave ai é “na classe abstrata”. Esse é o problema.

Basicamente vc quer fazer um esquema tipo template method. mas vc não precisa disso e isso não é flexivel. é muito mais simples vc criar uma classe especializada em executar pesquisas JDBC ( como o Spring faz) e depois injetar essa classe nas classes que precisam desse serviço.

É uma questão do design OO e o uso indevido de herança para reaproveitar codigo.

xdraculax

Entendi.

Realmente abstração (AbstractPersistence) não é usada em nenhum lugar realmente como uma abstração.
Ou seja, ninguém declara um tipo AbstractPersistence e usa-o sem sabe qual sua implementação.

Mas qual a principal vantagem de não herdar e usar uma classe “utilitária”?

Obs: (Injetar a classe utilitária nas classes de persistência realmente seria uma ótima decisão, mas não usamos Spring, pelas restrições que citei no inicio do post).

sergiotaborda

xdraculax:
Entendi.

Realmente abstração (AbstractPersistence) não é usada em nenhum lugar realmente como uma abstração.
Ou seja, ninguém declara um tipo AbstractPersistence e usa-o sem sabe qual sua implementação.

Mas qual a principal vantagem de não herdar e usar uma classe “utilitária”?

Várias vantagens mas a principal vantagem é desacoplamento.

Primeiro vc não vai usar o recurso de herança. Isso significa que vc pode herdar de outra coisa qq.
O recurso de herança é bala unica. se a usar uma vez, ja´era , portanto tem que se manter afastado de a usar o mais possivel.

Depois, herança tem a ver com categorias. Colocar um cara herdado AbstractPersistance não o categoriza realmente, mas do ponto de vista do java
sim. Faz sentido se vc tem algo como AbstractPersistance e depois herdando dele algo como XMLPErsistance, DBPersistance, CachePersistance. Vc está definindo um categoria de formas de persistencia. Mas fazer ProdutoPersistance, ClientePersistance, etc… não está categorizando nada, e pior, vc não consegue injetar mecanismos diferentes para a persistencia de produto, cliente, etc…


Obs: (Injetar a classe utilitária nas classes de persistência realmente seria uma ótima decisão, mas não usamos Spring, pelas restrições que citei no inicio do post).

A injeção é um principio que não depende de ferramentas ou containers. Passe o objeto no construtor do outro e pronto.

jurunaloco

pior que eu ja usei assim.. (é uma beleza :$)
ResultSet rGeral = ag.runSqlQuery("select * from produto where id_produto = " + cg.IntegerToSql(jTF_Produto.getText()));
mas o login eu usava preparedStatement..

e em conjunto usava:
public static void BeginTrans() {

        try {
            conexao.setAutoCommit(false);
        } catch (SQLException e) {
            System.err.println(e.getMessage());
        }
    }
e uma para Commit.

e para inserção eu fiz um framework leve usando classes anotadas. e jdbc puro

Criado 11 de fevereiro de 2010
Ultima resposta 25 de fev. de 2010
Respostas 30
Participantes 8