在不同泛型参数的抽象类中返回泛型是不好的做法

And*_*eou 6 java generics class

我有这个抽象类,我已经定义了一些实现数据库操作的方法(获取行,插入,删除等)

现在我想创建将返回一些行(即整个表)的方法,但是我希望它返回相应的模型类而不是域类(它基本上与域相同但没有关系列表和其他一些东西我不需要表示层).

抽象类是

public abstract class DomainService<T extends Domain> {

    protected abstract Logger getLogger();

    protected final Validator validator;

    protected DomainService() {
        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        this.validator = factory.getValidator();
    }

    abstract public void insert(T object) throws ValidationException;

    abstract public void delete(T object) throws EntityNotFoundException;

    abstract public List<T> fetchAll();
}
Run Code Online (Sandbox Code Playgroud)

我想添加另一个方法,它将调用fetchAll()然后迭代每个项目并创建等效的模型并返回列表.

public <K extends  Model> List<K> fetchAllModels(Class<K> modelClass) {
        List<T> domains = fetchAll();
        List<K> models = new ArrayList<K>(domains.size());

        for ( T domain : domains) {
            K model = modelClass.newInstance();
            models.add(model.fillIn(domain));
        }

        return models;
    }
Run Code Online (Sandbox Code Playgroud)

忽略这是我刚刚编写问题的代码,是否可以为类中未定义的泛型添加参数.IMO一个类可以有返回其他数据类型的方法,所以它应该不是问题.在我的情况下,我传递了类,所以我可以创建模型的实例,然后使用域来填充成员.我有两个意见,

  • 我写的那个,我在模型类中添加一个方法,从域对象创建它自己.我在想一个构造函数域对象作为参数,但我认为这是一个有点麻烦调用使用泛型构造函数(这将需要至少是反射公用事业),所以我虽然方法来填补使用默认构造函数创建实例后的详细信息.此外,模型位于更高层,我认为更高层应该使用更低层(数据库 - >域类 - >访问类(DAO) - >服务类 - > Servlet类----> JSP显示数据)

  • 我可以向域类添加一个方法,将域转换为其模型并调用它而不必传递模型的类

    public <K> List<K> fetchAllModels() {
        List<T> domains = fetchAll();
        List<K> models = new ArrayList<K>(domains.size());
    
        for ( T domain : domains) {
            models.add(domain.createModel());
        }
    
        return models;
    }
    
    Run Code Online (Sandbox Code Playgroud)

但我觉得域类应该像数据库中的表一样干净,只有与列有关的方法.

在类上添加参数会更好吗?我只会用它来做这个方法......

任何想法评论总是欢迎

Zho*_*gYu 5

为类中未定义的泛型添加参数是否可以接受

绝对地。它一直在做。

我更喜欢你的第一个解决方案,将模型传递给方法。

但是,您真正想要的是一个从 T 创建 K 的函数。在 java8 中,这可以非常简洁地完成。

public <K extends  Model> List<K> fetchAllModels(Function<T,K> func) {
...
            K model = func.apply(domain);
Run Code Online (Sandbox Code Playgroud)

并说你有一个域“D”的模型“M”

public M(D domain) // constructor
Run Code Online (Sandbox Code Playgroud)

您可以将构造函数传递为func(或至少看起来如此)

    service.fectchAllModels( M::new )
Run Code Online (Sandbox Code Playgroud)

如果你使用Stream,fetchAllModels()变得更简单

abstract public Stream<T> fetchAll();

public <K extends  Model> Stream<K> fetchAllModels(Function<T,K> func) {
    return fetchAll().map(func)
}
Run Code Online (Sandbox Code Playgroud)

然后,为什么我们甚至需要这种方法?做就是了

// fetch domains, convert each to M
Stream<M> models = service.fetchAll().map( M::new );
Run Code Online (Sandbox Code Playgroud)

所以我们可以fetchAllModels()从域中删除,并删除对模型的任何依赖。