2012-02-07 17 views
8

Actualmente tengo el siguiente código que recupera datos de la base de datos y luego crea un User. Este código se usa en muchos de mis classe para crear otros objetos como News, Comments etc ...constructores genéricos java

Utiliza apache commons dbutils.

final ResultSetHandler<User> handler = new ResultSetHandler<User>() { 

      @Override 
      public User handle(ResultSet rs) throws SQLException { 

       User user = null; 
       if (rs.next()) { 
        user = new User(); 
        user.setId(rs.getInt("id")); 
        user.setUsername(rs.getString("username")); 
        user.setPassword(rs.getString("password")); 
       } 
       return user; 
      } 
     }; 

     final User user = run.query(
       "SELECT id, username, password FROM users WHERE username = ? AND active = 2 LIMIT 1;", handler, 
       username); 

¿Sería posible envolver la QueryRunner en una clase genérica y anular el método de consulta para el controlador de la instanciate genérica T con el conjunto de resultados. Me aseguraría de que cualquier tipo de T tuviera un constructor que aceptara un ResultSet.

así:

 public class QueryExecuter<T> extends QueryRunner { 
    private ResultSetHandler<T> _handler; 

    public QueryExecuter(){//The T type was for testing haha 
     super(); 
     handler = new ResultSetHandler<T>() { 

      @Override 
      public T handle(ResultSet rs) throws SQLException { 

       T object = null; 
       if (rs.next()) { 
        object = new T(rs); 
       } 
       return object; 
      } 
     }; 
    } 
} 

No sé si vas a entender, pero lo espero, me pregunta si quieres más detalles o una mejor explicación.

EDITAR

pensé que podría utilizar un AbstractClass en lugar del tipo genérico que todos los objetos diferentes haría extiende, pero parece que no puedo escribir una constructora abstracto. Voy a tener que hacer un método estático que devuelve una instancia del objeto como:

public abstract class DatabaseEntity { 
    public static abstract DatabaseEntity create(ResultSet rs);//even this doesn't work... 
} 
+0

¿por qué necesita pasar 'T type' en el constructor? – yair

+0

use reflection, puede invocar el constructor de clase con el conjunto de resultados –

Respuesta

8

Posible, ¿sí? Pero es una mala idea.

Se podría hacer:

class ResultSetHandler<T> { 
    ResultSetHandler<T>(Class<T> clazz) { 
    this.clazz = clazz; 
    } 

    public T handle(ResultSet rs) throws SQLException { 
    T object = null; 
    if (rs.next()) { 
     object = clazz.getConstructor(ResultSet.class).newInstance(rs) 
    } 
    return object; 
    } 
} 

Mezcla de dominio y la base de datos es una mala idea, sin embargo. Lo que sería mejor, sin embargo, sería definir un método abtract que crea el objeto basado en el conjunto de resultados:

abstract class ResultSetHandler<T> { 

    protected abstract T create(ResultSet rs); 

    public T handle(ResultSet rs) throws SQLException { 
    T object = null; 
    if (rs.next()) { 
     object = create(rs); 
    } 
    return object; 
    } 
} 

A continuación, en la clase de implementación, sólo es necesario proporcionar un método create() vez de manejar el resultado configúrese usted mismo, por ejemplo:

h = new ResultSetHandler<Person>() { 
    protected Person create(ResultSet rs) { 
    return new Person(rs.getString("name")); 
    } 
} 
+0

+1 por proporcionar la misma respuesta que la mía, pero con buenos ejemplos de código. –

+0

Usted dice que mezclar la base de datos con el dominio no es una buena idea y lo entiendo, pero ¿qué haría para construir estos objetos a partir de los resultados de la consulta? – David

+0

Estoy usando una arquitectura MVC, por lo que mi modelo está ahí para su persistencia y sabe cómo guardar y actualizarse en la base de datos, pero yo uso una utilidad para realizar las consultas en la base de datos. Tal vez usar DAO? – David

0

no creo que es posible hacer esto en Java. No puede crear una instancia de T en un genérico. Los genéricos en java no son realmente plantillas como en C++, solo son azúcar de sintaxis alrededor de un object que elimina los moldes e induce advertencias de tiempo de compilación.

No hay manera como en C# de restringir T para que tenga un constructor.

Su mejor opción si esto es realmente necesario es resolver la clase apropiada mediante reflexión, pero incluso entonces se encontrará con un problema ya que no se puede conocer la clase de tiempo de ejecución de T cuando se invoca el método. Esta información se elimina el bytecode de java. Así que te queda pasar la clase al método para usar la reflexión sobre él. Y no estoy muy seguro de que esta sea una buena idea de diseño de todos modos.

+0

Puede hacerlo con reflejo, como dijo JB Nizet. –

+0

Definitivamente posible. Solo necesita una referencia a 'Clase '. –

+0

Sí, con reflejo. Aún necesitaría pasar la clase real al método. No puede ir a T.class como le gustaría hacer, si la información de la clase hubiera estado presente en el tiempo de ejecución. – Dervall

3

Podría hacer algo como eso (pasando la clase del objeto para crear, y usar el reflejo para llamar a su constructor), pero me parecería un mal diseño tener el POJO dependiente de JDBC, y saber no solo cómo se almacena en la base de datos, pero también qué alias se han utilizado en la consulta utilizada para cargarlo.

En resumen, no es responsabilidad del constructor del usuario POJO manejar un conjunto de resultados de una consulta externa desconocida.

podría diseñar una superclase AbstractSingleEntityHandler que acaba de tener el bloque

if (rs.next()) { 

, y va a delegar la creación entidad real a un método abstracto, pero no se ganaría mucho.

+0

+1 por ser más rápido que yo y escribir exactamente lo que quería;) –

+0

Estoy tratando de hacer esto porque el cuerpo del controlador que ves arriba en el primer bloque de código, se repite en cada consulta para cualquier objeto. Pensé que hubiera sido bueno asegurarme de que mis objetos que provienen de la base de datos saben cómo construirse a partir de un resultado de la consulta, el método 'query' devolvería directamente el objeto. – David

+0

¿Y qué quiere decir con POJO? – David