【问题标题】:Java - How to make overriding a method compulsory in child anonymous classes?Java - 如何在子匿名类中强制重写方法?
【发布时间】:2017-06-07 22:31:27
【问题描述】:

我一直在设计一些源代码,因为我们的项目中有很多代码在进行 SQL 查询时会重复。

所以我在下面做了这段代码,尝试类似于命令模式的东西似乎可以正常工作。它只接收一个字符串中的 SQL 查询和一些参数(如果需要)来设置语句。因此,您可以将此代码用作匿名类并执行查询,只定义如何处理查询的输出。

我的问题是我想设计它以强制在匿名子类中定义和编写方法 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});

【问题讨论】:

  • 你似乎知道该怎么做:将QueryCommand抽象化。有什么问题?
  • 好问题! :P

标签: java inheritance design-patterns overriding


【解决方案1】:

QueryCommand 抽象化,然后再创建一个具体的最终类。这样,任何匿名类都需要实现该方法,但您仍然有一个可以实例化的非抽象类(因为这显然是一个要求,尽管我不明白为什么)。

【讨论】:

  • 但是如果 AbstractQueryCommand 有一个最终的子 QueryCommand,我将如何在其中定义 getResult() 方法?
  • @madtyn 如果QueryCommand 是最终的,则不能有抽象方法,也不能在匿名类中覆盖它。所以它将在子类中定义。当然你总是可以添加一个Command 类来重新定义这个最终类的实现
  • @madtyn 你认为不能从抽象类中创建匿名类吗?我只包括了非抽象的 final 类,因为我认为你出于某种原因想要它。
  • @kayaman 是的,我认为这是不可能的。我缺乏知识...(-_-')
【解决方案2】:

如果不创建抽象方法和类,我想不出任何办法。

抽象类正是你需要的机制

我应该让另一个类能够实例化,它也不能是抽象的。

这是不正确的:匿名类完全能够继承抽象类,甚至扩展接口,当然前提是它们实现了所有抽象方法:

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;
    };
}

【讨论】:

  • 有趣。如果 QueryCommand 是抽象的并且我想以这种方式创建一个匿名类,您能否指定我将如何编写相同的使用示例?
  • 非常感谢您提供的代码 sn-p。我马上试试这个!
猜你喜欢
  • 2011-05-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-23
相关资源
最近更新 更多