Retornar ResultSet na classe abstrata

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.

[code]
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
}

}[/code]

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

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.

[quote=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.[/quote]

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.

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.

[quote=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.[/quote]

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.

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).

[quote=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.
[/quote]

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.

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).

[quote=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”?
[/quote]

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…

[quote]
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).[/quote]

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

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:

[code] public static void BeginTrans() {

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

[/code]
e uma para Commit.

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