接口使用与多态编码优化:无需实例化调用BaseDAO子类通用方法
嘿,这个问题我之前在项目里也踩过坑——每次new一个子类实例传进去确实挺繁琐的,尤其是子类多的时候,重复代码一堆。给你两个实用的方案,既能摆脱传新实例的麻烦,还能轻松统一调用所有子类的通用方法:
首先改造你的getDataFor方法,把参数从BaseDAO实例改成Class<? extends BaseDAO>,然后在方法内部通过反射创建实例(前提是所有子类都有无参构造,这也是DAO类的常规设计):
// 改造后的getDataFor方法 public void getDataFor(Class<? extends BaseDAO> daoClass) { try { // 通过无参构造创建子类实例 BaseDAO daoInstance = daoClass.getDeclaredConstructor().newInstance(); // 调用你的通用方法,比如 daoInstance.executeQuery() 或者其他接口方法 } catch (Exception e) { // 处理实例化异常,比如抛出运行时异常或记录日志 throw new RuntimeException("Failed to initialize DAO instance for " + daoClass.getName(), e); } }
这样单个调用就从getDataFor(new Program())简化成了getDataFor(Program.class),不用再手动new实例了。
如果要统一调用所有子类,只需要提前维护一个子类的Class集合,然后一行代码遍历调用:
// 提前定义所有BaseDAO子类的Class列表 private static final List<Class<? extends BaseDAO>> ALL_DAO_CLASSES = Arrays.asList( Program.class, UserDAO.class, OrderDAO.class // 把你的所有子类都加进来 ); // 统一调用所有子类的通用方法,一行搞定 ALL_DAO_CLASSES.forEach(this::getDataFor);
如果你的子类很多,手动维护列表太麻烦,还容易漏加新子类,可以用反射自动扫描指定包下的所有BaseDAO子类,不用手动维护列表。这里推荐用轻量级的Reflections库(专门做反射扫描的),或者也可以自己写简单的扫描逻辑(不过自己写要处理类加载器的细节)。
用Reflections的示例代码:
// 初始化扫描器,指定你的DAO类所在的包路径 Reflections reflections = new Reflections("com.yourproject.dao"); // 获取所有继承自BaseDAO的子类Class集合 Set<Class<? extends BaseDAO>> daoClasses = reflections.getSubTypesOf(BaseDAO.class); // 统一调用所有子类的通用方法 daoClasses.forEach(this::getDataFor);
这样哪怕后续新增了子类,只要放在指定包下,代码不用修改就能自动识别并调用,非常省心。
如果不想在getDataFor里写反射代码,可以单独抽一个工厂类,把实例化的逻辑封装起来,让代码更干净易维护:
public class DAOFactory { @SuppressWarnings("unchecked") public static <T extends BaseDAO> T createDAO(Class<T> daoClass) { try { return (T) daoClass.getDeclaredConstructor().newInstance(); } catch (Exception e) { throw new RuntimeException("Failed to create DAO instance", e); } } }
然后getDataFor就可以简化成:
public void getDataFor(Class<? extends BaseDAO> daoClass) { BaseDAO dao = DAOFactory.createDAO(daoClass); // 调用你的通用方法 }
注意事项
如果你的子类没有无参构造,那需要调整反射代码,比如获取带参数的构造器并传入必要参数,但一般来说,DAO类设计成无参构造是比较合理的选择,能让实例化逻辑更简单。
内容的提问来源于stack exchange,提问作者Volkeee

