想要在java中的复杂结构(DAO和服务层链接/耦合)上获得建议

时间:2012-11-05 19:54:48

标签: java oop design-patterns generics

简介

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

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

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

Diagram showing the DAO implementation for Product entities

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

  

实体的每个服务类至少会访问一个DAO对象,即它所针对的实体的DAO。

哪个是......

问题/问题

如果我可以为使每个服务类为其各自实体的DAO对象设置一个实例变量,那么我的服务层将是完美的,在我看来。 如果我的设计看起来不那么好,欢迎提出建议。

我已经像这样实现了它:

类AbstractService

public abstract class AbstractService<EntityDAO> {

    EntityDAO entityDAO;

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

    abstract EntityDAO makeEntityDAO();
}

Class ProductServiceImpl

public class ProductServiceImpl extends AbstractService<ProductDAOImpl> {

    public ProductServiceImpl() {
        super();
    }

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

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

我尽我所能包含您可能需要的所有内容,并且只包含您对此问题所需的内容。我现在要说的是,欢迎提出意见并提供更广泛的答案,感谢您花时间阅读。

StackOverflow上的其他资源

Understanding Service and DAO layers

DAO and Service layers (JPA/Hibernate + Spring)

1 个答案:

答案 0 :(得分:3)

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

  • 每个图层只知道下面的图层。
  • 它只知道它的接口,而不是它的实现类。

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

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

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

重要提示: 这个概念很棒而且功能强大,但简直就是愚蠢。您还可以使用Inversion of Control架构模式,而不需要框架,其中包含一个非常简单的实现,其中包含一个“组装”应用程序部件的大型静态方法。但在工业环境中,最好有一个框架,允许注入其他东西,如数据库连接,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>