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

如何多态控制不同接口类对象?不可修改Dao类时多态调用search方法

如何多态控制不同接口的Dao类对象

这是个很典型的「接口不统一但需要多态调用」的场景,既然不能修改原有Dao的源码,适配器模式(Adapter Pattern) 绝对是你的最佳选择——它就是专门用来解决这种「现有类接口不符合需求,但又不能改源码」的问题的。

下面给你一步步拆解实现思路:

1. 定义统一的目标接口

首先,我们需要先定一个所有Dao都要适配到的统一接口,比如叫Searchable,里面定义你期望的统一search方法签名。你可以根据实际业务调整参数和返回值,举个参考例子:

public interface Searchable {
    // 统一的搜索方法,用自定义查询条件类兼容不同Dao的参数,返回统一结果封装
    SearchResult search(SearchCondition condition);
}

这里的SearchCondition是你自己定义的通用查询条件类,用来适配各个Dao的不同查询参数;SearchResult则是通用结果封装类,用来统一不同Dao的返回类型。

2. 为每个现有Dao编写适配器类

接下来,为每个Dao(比如AaaDao、BbbDao...ZzzDao)写对应的适配器类,让它实现Searchable接口,同时持有对应Dao的实例,在适配器的search方法里完成「统一条件转Dao自有参数」和「Dao返回结果转统一结果」的逻辑。

举两个具体的适配例子:

例子1:适配AaaDao

假设AaaDao的原有搜索方法是:

// 原有AaaDao的接口(无法修改)
public class AaaDao {
    public List<Aaa> findByKeyword(String keyword, int pageSize) {
        // 原有实现逻辑
    }
}

对应的适配器类:

public class AaaDaoAdapter implements Searchable {
    // 持有原有Dao的实例
    private AaaDao aaaDao;

    // 通过构造器注入原有Dao对象
    public AaaDaoAdapter(AaaDao aaaDao) {
        this.aaaDao = aaaDao;
    }

    @Override
    public SearchResult search(SearchCondition condition) {
        // 1. 把统一的SearchCondition转换成AaaDao需要的参数
        String keyword = condition.getKeyword();
        int pageSize = condition.getPageSize();

        // 2. 调用原有Dao的搜索方法
        List<Aaa> aaaList = aaaDao.findByKeyword(keyword, pageSize);

        // 3. 把Aaa的结果转换成统一的SearchResult
        SearchResult result = new SearchResult();
        result.setData(aaaList);
        result.setTotal(aaaList.size());
        return result;
    }
}

例子2:适配BbbDao

假设BbbDao的原有搜索方法是另一种签名:

// 原有BbbDao的接口(无法修改)
public class BbbDao {
    public Bbb queryByIdAndName(Long id, String name) {
        // 原有实现逻辑
    }
}

对应的适配器类:

public class BbbDaoAdapter implements Searchable {
    private BbbDao bbbDao;

    public BbbDaoAdapter(BbbDao bbbDao) {
        this.bbbDao = bbbDao;
    }

    @Override
    public SearchResult search(SearchCondition condition) {
        // 转换参数
        Long id = condition.getEntityId();
        String name = condition.getEntityName();

        // 调用原有方法
        Bbb bbb = bbbDao.queryByIdAndName(id, name);

        // 转换结果
        SearchResult result = new SearchResult();
        if (bbb != null) {
            result.setData(Collections.singletonList(bbb));
            result.setTotal(1);
        } else {
            result.setData(Collections.emptyList());
            result.setTotal(0);
        }
        return result;
    }
}

3. 多态调用统一接口

现在,你就可以把所有适配器当作Searchable接口的实现类来多态使用了:

public class Client {
    public static void main(String[] args) {
        // 初始化各个Dao和对应的适配器
        Searchable aaaSearcher = new AaaDaoAdapter(new AaaDao());
        Searchable bbbSearcher = new BbbDaoAdapter(new BbbDao());
        // ... 其他ZzzDao的适配器

        // 把所有搜索器放到统一的集合里
        List<Searchable> searchers = Arrays.asList(aaaSearcher, bbbSearcher);

        // 构造统一的查询条件
        SearchCondition condition = new SearchCondition();
        condition.setKeyword("test");
        condition.setPageSize(10);
        condition.setEntityId(1L);
        condition.setEntityName("demo");

        // 多态调用search方法!
        for (Searchable searcher : searchers) {
            SearchResult result = searcher.search(condition);
            // 处理统一的结果
            System.out.println("搜索结果总数:" + result.getTotal());
        }
    }
}

备选方案:反射(不推荐)

如果你觉得写几十个适配器太麻烦,也可以用反射来调用不同的search方法,但这种方式类型不安全,而且代码可读性差,后期维护成本高,只有在适配器数量极多且逻辑非常简单的情况下才考虑。比如:

public Object searchWithReflection(Object dao, SearchCondition condition) throws Exception {
    // 根据dao的类型获取对应的方法名和参数
    Method method = dao.getClass().getMethod("findByKeyword", String.class, int.class);
    return method.invoke(dao, condition.getKeyword(), condition.getPageSize());
}

但还是强烈推荐适配器模式,它是类型安全的,而且逻辑清晰,后期扩展新Dao的时候只需要加一个新的适配器即可,完全符合开闭原则。

内容的提问来源于stack exchange,提问作者Tando

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 08:52:54