【问题标题】:Is it bad practice to return a generic inside an abstract class of different generic parameter在不同泛型参数的抽象类中返回泛型是不好的做法
【发布时间】:2015-05-19 14:57:02
【问题描述】:

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

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

抽象类是

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)-> 服务类-> 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;
    }
    

但我觉得域类应该是数据库中表的简洁表示,唯一的方法与列有关。

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

欢迎任何想法的cmets

【问题讨论】:

  • 不确定我是否得到了你,但是是的;如果您具有仅单个方法所需的类型参数;那么您实际上应该这样做 - 无需将其设为类范围的参数。
  • 如果我错了,请纠正我,但我认为选项 B 由于类型推断而无法工作,Java 编译器如何仅根据类型信息推断类型 K T?
  • 忽略上述,我混淆了问题。 K 扩展了 Model,它是基础抽象类。 domain#createModel 返回模型类型。
  • @AndreasAndreou 那么您可能应该明确指出&lt;K extends Model&gt; 吗?
  • @AndreasAndreou,是的,对于 fillIn/createModel 方法,我不喜欢将 logic 插入 data 对象(DTO、POJO、...),因为它混合了关注点并且不尊重模型和域之间的分离。我更喜欢在每个具体实现中手动将转换编码为私有方法,或者使用诸如dozer 之类的工具

标签: java class generics


【解决方案1】:

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

当然。一直都这样。

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

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

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

并假设您有一个用于域“D”的模型“M”

public M(D domain) // constructor

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

    service.fectchAllModels( M::new )

如果你使用StreamfetchAllModels() 会变得更简单

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(),并从域中删除对模型的任何依赖。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多