6

介绍

我试图用接口、抽象类和泛型在 Java 中创建一个相当复杂的结构。没有使用泛型的经验,只有创建良好 OOP 设计的平均经验,这开始被证明是一个相当大的挑战。

我有一种感觉,我正在尝试做的事情实际上无法完成,但我可以足够接近它。我会尽量简短地解释它。我只想直接告诉大家,这个结构将代表我的 DAO 和服务层来访问数据库。使这个问题更抽象只会使它变得更加困难。

我的 DAO 层完全没有问题。有一个通用 DAO 接口,对于每个实体,都有一个 DAO 接口扩展通用接口并填充通用类型。然后是每个 DAO 实现扩展的抽象类,它又实现了相应的接口。最有可能令人困惑,所以下面的图表显示了产品的 DAO 作为示例:

显示产品实体的 DAO 实现的图表

现在对于服务类,我想到了类似的结构。无论如何,服务类中的大多数方法都映射到 DAO 方法。如果将上图中的每个“DAO”都替换为“Service”,就得到了我的服务层的基础。但是基于我的以下想法,我想做一件事:

实体的每个服务类都将至少访问一个 DAO 对象,即为其设计的实体的 DAO。

哪个是...

问题/问题

在我看来,如果我可以进行适当的 OO 设计,使每个服务类都有一个用于其各自实体的 DAO 对象的实例变量,那么我的服务层将是完美的。欢迎对此提出建议,以防我的设计不像看起来那么好。

我已经这样实现了:

类 AbstractService

public abstract class AbstractService<EntityDAO> {

    EntityDAO entityDAO;

    public AbstractService() {
        entityDAO = makeEntityDAO(); //compiler/IDE warning: overridable method call in constructor
    }

    abstract EntityDAO makeEntityDAO();
}

类 ProductServiceImpl

public class ProductServiceImpl extends AbstractService<ProductDAOImpl> {

    public ProductServiceImpl() {
        super();
    }

    @Override
    ProductDAOImpl makeEntityDAO() {
        return new ProductDAOImpl();
    }
}

这种设计的问题是我不喜欢编译器警告:它在构造函数中有一个可覆盖的方法调用(参见注释)。现在它被设计为可覆盖的,实际上我强制它以确保每个服务类都有对相应 DAO 的引用。这是我能做的最好的事情吗?

我已尽我最大的努力包含您可能需要的所有内容,并且仅包含此问题所需的内容。我现在要说的是,欢迎评论和更广泛的答案,感谢您抽出宝贵的时间阅读。

StackOverflow 上的其他资源

了解服务和 DAO 层

DAO 和服务层(JPA/Hibernate + Spring)

4

1 回答 1

3

首先要注意一点:通常在像 Presentation / Service / DAO 这样的层中组织的应用程序中,您有以下规则:

  • 每一层只知道紧接其下的层。
  • 它只通过它的接口知道它,而不是通过它的实现类。

这将提供更容易的测试、更好的代码封装和更清晰的不同层定义(通过易于识别为公共 API 的接口)

也就是说,有一种非常常见的方法可以以最灵活的方式处理这种情况:依赖注入Spring是依赖注入(以及许多其他东西)的行业标准实现

这个想法(简而言之)是您的服务将知道它需要一个 IEntityDAO,并且有人会在实际使用服务之前将其注入并实现接口。那个人被称为 IOC 容器(Inversion of Control容器)。它可以是Spring,它的作用通常由应用程序配置文件描述,并将在应用程序启动时完成。

重要提示:这个概念非常出色和强大,但非常简单愚蠢。您还可以在没有框架的情况下使用控制反转架构模式,其实现非常简单,包括一个大型静态方法“组装”您的应用程序部分。但在工业环境中,最好有一个允许注入其他东西的框架,如数据库连接、Web 服务存根客户端、JMS 队列等......

好处:

  • 您可以轻松地进行模拟和测试,因为类唯一依赖的就是接口
  • 您有一个包含一小组 XML 文件的单个文件,这些文件描述了您的应用程序的整个结构,这在您的应用程序增长时非常方便。
  • 这是一个非常广泛采用的标准,并且为许多 Java 开发人员所熟知。

示例java代码:

public abstract class AbstractService<IEntityDAO> {

    private IEntityDAO entityDAO; // you don't know the concrete implementation, maybe it's a mock for testing purpose

    public AbstractService() {
    }

    protected EntityDAO getEntityDAO() { // only subclasses need this method
    }

    public void setEntityDAO(IEntityDAO dao) { // IOC container will call this method
        this.entityDAO = dao;
    }
}

在 spring 配置文件中,您将拥有类似的内容:

<bean id="ProductDAO" class="com.company.dao.ProductDAO" />

[...]

<bean id="ProductService" class="com.company.service.ProductService">
    <property name="entityDAO" ref="ProductDAO"/>
</bean>
于 2012-11-05T22:39:36.497 回答