为子类的泛型实现的 Class' 变量提供扩展功能

Provide Extended Functionality to Generic's Implemented Class' Variable to Subclass

我是泛型的新手,正在研究基本上超出我知识范围的事情,所以请多多包涵。也许我问的是愚蠢的,但我似乎无法找到关于我想做的事情是否可行的明确答案,也许是因为我不知道要寻找的正确术语。

我有两个 Java classes,它们用 T 类型的实体参数化 - 一个存储库和一个服务。由于我所有的存储库和我的所有服务都将执行一些相同的基本任务,因此我的通用存储库和服务已经实现了上述任务,并通过受保护的功能将它们提供给任何扩展它们的东西。到目前为止,一切都很顺利。目前它们看起来像这样:

存储库class:

public interface GenericRepo<T> {
    protected T findObject();
}

服务class:

public class GenericService<T> {
    private GenericRepo<T> repo;

    public GenericService(GenericRepo<T> repo) {
        this.repo = repo;
    }

    protected T findObject() {
        return this.repo.findObject();
    }
}

当我希望扩展我的服务并允许人们使用存储库的 subclass 时,问题就来了。虽然许多实体是基本的并且功能包含在通用功能中,但有时需要特殊情况才能对实体执行附加功能。在设置中,repo 是 implemented/extended,然后扩展的 class 被传递给服务(它接受它,因为它是 GenericRepo<T> 的一种类型)。具体的回购协议如下所示:

public class ExtendedRepo implements GenericRepo<Entity> {
   protected Entity findObjectByWeirdKeyOnEntity(String weirdKey) {
       //awesome code that does stuff here
   }
}

我还将该服务声明为通用服务,因为该服务也有很多自定义功能的可能性。因此,GenericService 也扩展如下:

public class ExtendedService extends GenericService<Entity> {
    public ExtendedService(ExtendedRepo repo) {
        super(repo);
    }

    public Entity findObjectByWeirdKeyOnEntity() {
        // Do stuff to generate weird key to search by
        return this.repo.findObjectByWeirdKeyOnEntity(weirdKey);
    }
}

这使我可以在服务上执行自定义功能,还可以利用通用服务上的所有基本功能,而无需复制代码。但是,因为 GenericService 中的变量 repo 被声明为 GenericRepo<T> 类型,所以只有那些实际上属于 GenericRepo<T> 类型的函数才可用于通用服务 class and/or 任何扩展它的东西。因此,尽管我正在将 ExtendedRepo 传递给我的 ExtendedService,我的 ExtendedService 的超级 class 已经创建并通过子 GenericRepo class 提供了一个实例class 的 ExtendedRepo,我无法使用 GenericService 上声明的变量来调用 ExtendedRepo 上的任何函数。 上面代码块中的代码失败 - this.repo 不知道函数 findObjectByWeirdKeyOnEntity 因为它是类型 GenericRepo<T> 的变量。目前要在扩展存储库上使用任何自定义函数,我已经完成了以下操作:

public class ExtendedService extends GenericService<Entity> {
    private ExtendedRepo extendedRepo;

    public ExtendedService(ExtendedRepo repo) {
        super(repo);
        this.extendedRepo = repo;
    }

    public Entity findObjectByWeirdKey() {
        return this.extendedRepo.findObjectByWeirdKeyOnEntity(weirdKey);
    }
}

在扩展服务中为存储库重新声明并保留一个单独的变量似乎是错误的,因为我基本上保留了相同 class 的两个实例,这样我就可以在扩展服务中使用一个自定义函数 class 同时还使用了超级 class 的所有常用功能。有什么方法可以在 GenericService 上创建变量 GenericRepo 使其成为扩展 GenericRepo 的任何类型,这将允许扩展 GenericService 的 classes 使用GenericRepo class?

扩展版本的自定义方法

您可以向 GenericService 添加一个类型参数,它将代表 GenericRepo 的类型:

public class GenericService<R extends GenericRepo<T>, T> {
    protected R repo;

    public GenericService(R repo) {
        this.repo = repo;
    }

    protected T findObject() {
        return this.repo.findObject();
    }
}

public class ExtendedService extends GenericService<ExtendedRepo, Entity> {
    public ExtendedService(ExtendedRepo repo) {
        super(repo);
    }

    public Entity findObjectByWeirdKeyOnEntity(String weirdKey) {
        return this.repo.findObjectByWeirdKeyOnEntity(weirdKey);
    }
}

注意:在您的最后一个示例中,您保留了对同一实例的两个引用,而不是对同一实例的两个引用class.

GenericService 有一个 repo 类型 GenericRepo。你在 ExtendedService 的构造函数中所做的事情只会在运行时可见,即 repo 实例的运行时类型将是 ExtendedService 类型(前提是它在 ExtendedService 对象)。
但是在编译时,repo 是类型 GenericRepoGenericRepo 没有方法 findObjectByWeirdKeyOnEntity.
因此,如果您想在 ExtendedService class 中使用它,则必须明确地将其大小写为 ExtendedService。所以只需这样做: return ((ExtendedRepo)this.repo).findObjectByWeirdKeyOnEntity(weirdKey);

使用。这也是一个很好的。