You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让父类DataModel的all()方法返回子类实例列表?

通用DataModel父类实现方案:泛型+反射适配子类类型

这个需求刚好可以通过泛型方法+抽象类+反射来解决,既能让父类保持通用性,新增子类时也不用修改父类代码,完美符合开闭原则。下面一步步给你拆解实现方案:

1. 重构DataModel为抽象父类

首先把DataModel改成抽象类,定义子类必须实现的核心方法(表名、列定义、数据填充),同时实现通用的all()泛型方法:

import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public abstract class DataModel {
    // 抽象方法:子类必须返回自己对应的数据库表名
    protected abstract String getTableName();
    
    // 抽象方法:子类必须返回自己对应的列名-类型映射
    protected abstract Map<String, String> getColumns();
    
    // 抽象方法:子类负责将数据库查询结果填充到自身字段
    protected abstract void populate(Map<String, Object> rowData);

    /**
     * 通用查询方法:返回指定子类类型的实例列表
     * @param modelClass 子类的Class对象
     * @return 子类实例组成的ArrayList
     */
    @SuppressWarnings("unchecked")
    public static <T extends DataModel> ArrayList<T> all(Class<T> modelClass) {
        ArrayList<T> dataList = new ArrayList<>();
        
        try {
            // 1. 通过反射创建子类实例,获取表名和列定义
            Constructor<T> emptyConstructor = modelClass.getDeclaredConstructor();
            T tempInstance = emptyConstructor.newInstance();
            String tableName = tempInstance.getTableName();
            Map<String, String> columns = tempInstance.getColumns();

            // 2. 调用数据库服务查询数据(这里假设getAllMatchesFromTable返回多行数据,类型为List<Map<String, Object>>)
            List<Map<String, Object>> queryResults = LocalStorageServices.DatabaseService()
                    .getAllMatchesFromTable(tableName, columns);

            // 3. 遍历查询结果,创建子类实例并填充数据
            Constructor<T> columnConstructor = modelClass.getDeclaredConstructor(Map.class);
            for (Map<String, Object> row : queryResults) {
                T model = columnConstructor.newInstance(columns);
                model.populate(row);
                dataList.add(model);
            }

        } catch (Exception e) {
            // 捕获反射和数据库异常,包装为运行时异常抛出
            throw new RuntimeException("Failed to load data for model: " + modelClass.getName(), e);
        }
        
        return dataList;
    }

    // 父类构造方法:供子类继承
    protected DataModel() {}
    
    protected DataModel(Map<String, String> columns) {
        // 可添加通用初始化逻辑,比如保存列定义
    }
}

2. 子类实现示例(User类)

子类只需要继承DataModel,实现三个抽象方法,再添加自己的业务字段和方法即可。如果想让调用更简洁,还可以添加一个静态all()方法封装父类调用:

import java.util.HashMap;
import java.util.Map;

public class User extends DataModel {
    // 子类业务字段
    private String username;
    private String email;

    // 数据库表名常量
    private static final String TABLE_NAME = "testing";

    @Override
    protected String getTableName() {
        return TABLE_NAME;
    }

    @Override
    protected Map<String, String> getColumns() {
        Map<String, String> columns = new HashMap<>();
        columns.put("username", "TEXT");
        columns.put("email", "TEXT");
        return columns;
    }

    @Override
    protected void populate(Map<String, Object> rowData) {
        // 将查询结果映射到子类字段
        this.username = (String) rowData.get("username");
        this.email = (String) rowData.get("email");
    }

    // 封装父类方法,让调用更直观
    public static ArrayList<User> all() {
        return DataModel.all(User.class);
    }

    // 子类自定义方法
    public void sendWelcomeEmail() {
        System.out.println("Sending email to: " + this.email);
    }

    // 构造方法:继承父类
    public User() {
        super();
    }

    public User(Map<String, String> columns) {
        super(columns);
    }
}

3. 调用方式

现在你可以直接用想要的方式调用,返回的列表不需要强制转换,直接是子类类型:

// 调用子类的all()方法,获取User实例列表
ArrayList<User> appUsers = User.all();

// 直接调用子类的业务方法
for (User user : appUsers) {
    user.sendWelcomeEmail();
}

4. 新增子类(比如Entry、Post)的适配

当你需要新增Entry或Post模型时,只需要重复User类的步骤:

  • 继承DataModel
  • 实现getTableName()、getColumns()、populate()三个抽象方法
  • 添加自己的业务字段和方法
  • 可选:添加静态all()方法封装调用

完全不需要修改父类代码,完美适配你的需求。

注意事项

  • 确保子类提供了无参构造和接收Map<String, String>的构造方法(供反射调用)
  • 数据库查询方法getAllMatchesFromTable的返回类型建议调整为List<Map<String, Object>>,因为单条Map无法表示多行查询结果(你原来的代码里返回Map<String, Object>可能是个小问题)
  • 反射过程中的异常建议捕获并包装为运行时异常,避免上层代码处理繁琐的受检异常

内容的提问来源于stack exchange,提问作者Javier Torron Diaz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 06:56:38