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

时间:2015-05-19 14:57:03

标签: java class generics

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

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

抽象类是

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

我想添加另一个方法来调用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;
    }

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

  • 我写的那个,我在模型类中添加一个方法,从域对象创建它自己。我正在考虑一个构造函数,它将域对象作为参数,但我认为使用泛型调用构造函数有点麻烦(它至少需要反射实用程序)所以我虽然有一个方法使用默认构造函数创建实例后填充详细信息。此外,模型位于更高层,我认为更高层应使用更低层(数据库 - >域类 - >访问类(DAO) - >服务类 - &gt; Servlet类----&gt; 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;
    }
    

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

在类上添加参数会更好吗?我只会将它用于这种方法...

任何想法总是欢迎评论

1 个答案:

答案 0 :(得分:4)

  

是否可以为未在类

中定义的泛型添加参数

绝对。它一直在做。

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

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

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

并说你有一个模特&#39; M&#39;对于域名&#39; <&#39;

public M(D domain) // constructor

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

    service.fectchAllModels( M::new )

如果您使用Stream,则fetchAllModels()变得更加简单

abstract public Stream<T> fetchAll();

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

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

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

因此,我们可以删除fetchAllModels(),并从域中删除对模型的所有依赖项。