2017-01-23 12 views
2

Я разрабатывал некоторый исходный код, потому что в нашем проекте много кода повторялось при выполнении SQL-запросов.Java - Как сделать переопределение метода обязательным в дочерних анонимных классах?

Итак, я сделал этот код ниже, который, кажется, отлично работает, используя что-то похожее на шаблон команды. Он получает только SQL-запрос в String и некоторые параметры (если необходимо) для установки в инструкции. Таким образом, вы можете использовать этот код как анонимный класс, чтобы выполнить запрос, определяя, что делать с выходом запроса.

Моя проблема заключается в том, что я хотел создать это, чтобы сделать обязательным определение и запись метода getResult в анонимном дочернем классе, но я не могу думать об этом, не делая абстрактного метода и класса.

Если QueryCommand становится абстрактным, я должен сделать еще один класс, чтобы иметь возможность создавать экземпляр, что также не может быть абстрактным. Есть ли другой способ сделать обязательным переопределение в классе детей? Я ищу самый умный простейший способ добиться этого.

Не знал, как искать подобный шаблон или решение.

Заранее спасибо.

код Источник:

import java.sql.Connection; 
import java.sql.SQLException; 

public interface IQueryCommand<T> { 
    T executeQuery(Connection conn, String query, Object... args) throws SQLException; 
} 


import java.math.BigDecimal; 
import java.sql.CallableStatement; 
import java.sql.Connection; 
import java.sql.PreparedStatement; 
import java.sql.ResultSet; 
import java.sql.SQLException; 
import java.text.MessageFormat; 
import org.apache.log4j.Logger; 

public class QueryCommand<T> implements IQueryCommand<T> { 
    private Logger LOGGER = Logger.getLogger(this.getClass()); 

    /** The constant ERROR_CLOSING_RESULT_SET */ 
    protected static final String ERROR_CLOSING_RESULT_SET = "Error when closing ResultSet"; 

    /** The Constant ERROR_CLOSING_PREPARED_STATEMENT. */ 
    protected static final String ERROR_CLOSING_PREPARED_STATEMENT = "Error when closing PreparedStatement"; 

    // FIXME: I want this method to be mandatory to be defined in the anonymous child class 
    protected T getResult(ResultSet rs) throws SQLException { 
     return null; 
    }; 


    public T executeQuery(Connection conn, String sqlQuery, Object... args) throws SQLException { 
     if (LOGGER.isDebugEnabled()) { 
      LOGGER.debug(sqlQuery); 
     } 
     PreparedStatement ps = null; 
     ps = conn.prepareStatement(sqlQuery); 

     return executeQuery(conn, ps, args); 
    } 

    public T executeQuery(Connection conn, PreparedStatement ps, Object... args) throws SQLException { 
     ResultSet rs = null; 
     try { 
      if(args != null && args.length > 0) {   
       for(int i=0; i< args.length; i++) { 
        setArg(ps, i+1, args[i]); 
       } 
      } 
      rs = ps.executeQuery(); 
      T result = getResult(rs); // Method defined in child class 

      return result; 
     } catch (SQLException e) { 
      throw e; 
     } finally {  
      if(rs != null) { 
       try { 
        rs.close(); 
       } catch (final SQLException e) { 
        LOGGER.error(ERROR_CLOSING_RESULT_SET, e); 
       } 
      } 
      if (ps != null) { 
       try { 
        ps.close(); 
       } catch (final Exception e) { 
        if(ps instanceof CallableStatement) { 
         LOGGER.error("Error when closing CallableStatement", e); 
        } else if(ps instanceof PreparedStatement) { 
         LOGGER.error(ERROR_CLOSING_PREPARED_STATEMENT, e); 
        } 
       } 
      } 
     } 
    } 


    /** 
    * Sets a value on the PreparedStatemente with a method dependending on dataType 
    * 
    * @param ps the preparedStatement 
    * @param idx the index on which the value is set 
    * @param value the value to set 
    * @throws SQLException if an error is detected 
    */ 
    private void setArg(PreparedStatement ps, int idx, Object value) throws SQLException { 
     // Implementation not relevant... 
    } 
} 

Пример того, как использовать этот:

sqlQuery = " SELECT X FROM Y WHERE countryId = ? and languageId = ?"; 
return new QueryCommand<String>() { 
    // This method should be REQUIRED when compiling 
    @Override 
    protected String getResult(ResultSet rs) throws SQLException { 
     String result = ""; 
     while (rs.next()) { 
      result = rs.getString("DESCRIPTION"); 
     } 
     return result; 
    }; 
}.executeQuery(getDB2Connection(), sqlQuery.toString(), new Object[] { countryIdParameter, languageIdParameter}); 
+1

Вы, кажется, знаете что делать: сделайте аннотация «QueryCommand». Что за вопрос? –

+1

Отличный вопрос! : P –

ответ

6

Я не могу думать об этом, не делая абстрактного метода и класса.

Абстрактный класс именно тот механизм, который вам нужен

я должен сделать еще один класс, чтобы иметь возможность создать экземпляр, который не может быть абстрактным, а также.

Это не так: анонимные классы вполне способны наследовать абстрактный класс, или даже расширения интерфейса, при условии, конечно, что они реализуют все абстрактные методы:

public class AbstractQueryCommand<T> implements IQueryCommand<T> { 
    abstract protected String getResult(ResultSet rs) throws SQLException; 
    ... 
} 
return new AbstractQueryCommand<String>() { 
    @Override 
    protected String getResult(ResultSet rs) throws SQLException { 
     String result = ""; 
     while (rs.next()) { 
      result = rs.getString("DESCRIPTION"); 
     } 
     return result; 
    }; 
} 
+0

Интересно.Не могли бы вы указать, как мне написать тот же пример использования, если QueryCommand был абстрактным, и я хотел сделать анонимный класс таким образом? – madtyn

+0

Большое спасибо за фрагмент кода. Я пробую это прямо сейчас! – madtyn

2

Сделать QueryCommand абстрактный, а затем создать дополнительный конкретный конечный класс. Таким образом, любой анонимный класс должен реализовать этот метод, но у вас все еще есть не абстрактный класс, который вы можете создать (поскольку это было, по-видимому, требованием, хотя я не понимаю почему).

+0

Но если AbstractQueryCommand имеет дочерний QueryCommand, который был бы окончательным, как бы я определил метод getResult() в нем? – madtyn

+0

@madtyn, если 'QueryCommand' является окончательным, вы не можете иметь абстрактный метод и не можете переопределить его в анонимном классе. Поэтому он будет определен в дочернем классе. Конечно, вы всегда можете добавить класс 'Command', чтобы переопределить реализацию этого окончательного класса. – AxelH

+0

@madtyn. Считаете ли вы, что вы не можете создать анонимный класс из абстрактного класса? Я включил не абстрактный абстрактный класс, потому что по какой-то причине я думал, что вы этого хотели. – Kayaman