如何在模块化应用程序中处理通用 类 / 接口?

How to handle generic classes / interfaces in a modular application?

我是 Java 的新手,我正在编写这样的模块化应用程序:

*************          *******         ***********
*           *          *     *         *   Data  *
* Front-end * -------- * API * ------- * Handler *
*           *          *     *         *         *
*************          *******         ***********

本质上,我希望能够用 N classes 定义一个 API,然后让一个 "Data Handler" 模块处理将对象存储在某处(一个数据库,对于例如),而前端不需要知道它是如何实现的。

所以,假设我在 API 中定义了两个 class:Contract 和 Company。 我希望前端能够做类似的事情:

myContract = new Contract();
myCompany = new Company();
myContract.setCompany(myCompany);
myContract.save();
myCompany.save();

这样,以后我可以改变存储数据的方式(Data Handler 模块),而无需更改前端的任何代码。

为此,我在 API 模块中为 Contract 和 Company 编写了两个接口。 然后,在数据处理程序模块中,我写了 classes 实现了两个接口:DbContract 和 DbCompany。

现在,我 运行 遇到了问题,因为我已经将 Contract 接口中的 getter/setter 方法定义为:

public interface Contract {
    public Company getCompany();
    public void setCompany(Company company);
}

并在 DbContract 中将它们实现为:

public class DbContract implements Contract {
    private DbCompany company;

    @Override
    public Company getCompany() {
        return this.company;
    }

    @Override
    public void setCompany(Company company) {
        this.company = company;
    }
}

但是,我到处都是 class 类型不匹配错误... 我完全错过了重点吗?我应该怎么做?

在此先感谢您的帮助。

myContract = new Contract();

这行不通,因为您无法创建接口的实例。

您的想法似乎是正确的,但似乎对术语有误解"implementation"。

如果前端需要创建这些接口的实例,它需要知道一个实现或提供自己的实现。另一方面,如果前端根本不应该知道实现,它应该调用后端来创建一个新实例。

除此之外,制作 ContractCompany 数据容器并将实际保存逻辑移动到服务中可能是更好的设计,例如您的代码将如下所示:

class Contract { ... } //as before, but classes not interfaces
class Company { ... } //as before, but classes not interfaces

创建新合约:

Contract myContract = new Contract();
Company myCompany = new Company();
myContract.setCompany(myCompany);

contractService.save( myContract ); //assuming this would save the company as well

您可以查找该服务或让它被注入。对于后者,请查看 Spring 依赖注入。

更新:

在您的评论中,您声明 CompanyContract 将是 JPA 实体,如果我理解正确的话,您不希望前端知道正在使用 JPA。

在这种情况下,您有两个选择:

  1. 使您的对象成为纯 POJO,并在后端为 JPA 映射添加一个 XML。然后,您将从前端传递的每个实例都视为分离的实体。

  2. 如果你想为映射使用注解并且不想让前端知道你需要提供一个中间层(称为数据传输对象= DTO ) 由 API 使用。然后后端将在实体和 DTO 之间进行内部转换。

改变

    private DbCompany company;

    private Company company;

每样东西都应该是甜蜜的。

否则,您将需要前端了解您正在处理的公司类型并通用。 这还没有被编译但是是这样的:

public interface Contract<T extends Company>{
    public T getCompany();
    public void setCompany(T company);
}

public class DbContract implements Contract<DbCompany> {
    private DbCompany company;

    @Override
    public DbCompany getCompany() {
        return this.company;
    }

    @Override
    public void setCompany(DbCompany company) {
        this.company = company;
    } 
}