6

Introduction

I am trying to make a rather complex structure in Java with interfaces, abstract classes and generics. Having no experience with generics and only average experience with creating good OOP designs, this is beginning to prove quite a challenge.

I have some feeling that what I'm trying to do cannot actually be done, but that I could come close enough to it. I'll try to explain it as brief as I can. I'm just going to tell straight away that this structure will represent my DAO and service layers to access the database. Making this question more abstract would only make it more difficult.

My DAO layer is completely fine as it is. There is a generic DAO interface and for each entity, there is a DAO interface that extends the generic one and fills in the generic types. Then there's an abstract class that is extended by each DAO implementation, which in turn implement the corresponding interface. Confusing read for most probably, so here's the diagram showing the DAO for Products as an example:

Diagram showing the DAO implementation for Product entities

Now for the service classes, I had a similar construction in mind. Most of the methods in a service class map to the DAO methods anyway. If you replace every "DAO" in the diagram above with "Service", you get the basis for my service layer. But there is one thing that I want to do, based on the following idea I have:

Every service class for an entity will at least access one DAO object, namely the DAO of the entity that it is designed for.

Which is...

The question/problem

If I could make a proper OO design to make each service class have one instance variable for the DAO object of their respective entity my service layer would be perfect, in my view. Advice on this is welcome, in case my design is not so good as it seemed.

I have implemented it like this:

Class 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();
    }
}

The problem with this design is a compiler warning I don't like: it has an overridable method call in the constructor (see the comment). Now it is designed to be overridable, in fact I enforce it to make sure that each service class has a reference to the corresponding DAO. Is this the best thing I can do?

I have done my absolute best to include everything you might need and only what you need for this question. All I have to say now is, comments are welcome and extensive answers even more, thanks for taking your time to read.

Additional resources on StackOverflow

Understanding Service and DAO layers

DAO and Service layers (JPA/Hibernate + Spring)

Community
  • 1
  • 1
MarioDS
  • 12,895
  • 15
  • 65
  • 121
  • You won't have to make a call to an overridable method if you instantiate your DAO in the constructor of `AbstractService` this way: `entityDao = (Class) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];` – Attila T Nov 05 '12 at 20:45
  • in your service level you probably want to make it more abstract, i.e. Do not define the references to you DAO to the concrete implementations as that will make it tightly coupled. i would use the abstract implementation and inject the concrete implementation using some form of dependency injection, which can be achieved in several ways that way you can get rid of the makeDAOEntity method all together and have it handled by the dependency injection method you choose – Modika Nov 05 '12 at 20:49
  • @AttilaT. then I think i'd rather go with the compiler warning than with reflection and something totally unreadable... – MarioDS Nov 05 '12 at 21:05
  • @Modika Dependency injection is something totally new to me. Wouldn't this make the whole thing more complex than necessary? Also there is always a link between service and DAO. I agree that coupling will be tight that way, but only between DAO and Service that are relevant to the same entity... – MarioDS Nov 05 '12 at 21:07
  • DI woukd still maintain the link just in an abstract way. the concept is not that hard to grasp you are just injecting concrete dependencies when you need them and decoupling your application from the concrete implementations will make less conpmex and easier to manage. Sorry that i cant give an example as i dont know what java has available – Modika Nov 06 '12 at 07:17
  • @MarioDeSchaepmeester I thought your only problem was the compiler warning (which by the way should be treated much more seriously as many articles on the net are already discussing it in detail, search for "calling overridable method from constructor"). You got the majority of the design right IMO except for the dependency injection part but this issue has already got addressed below. – Attila T Nov 06 '12 at 13:24
  • @AttilaT. Thanks, I will look into dependency injection. – MarioDS Nov 06 '12 at 13:47

1 Answers1

3

Just a little note first: usually in an application organized in layers like Presentation / Service / DAO for example, you have the following rules:

  • Each layer knows only the layer immediately below.
  • It knows it only by it's interfaces, and not by it's implementation class.

This will provide easier testing, a better code encapsulation, and a sharper definition of the different layers (through interfaces that are easily identified as public API)

That said, there is a very common way to handle that kind of situation in a way that allow the most flexibility: dependency injection. And Spring is the industry standard implementation of dependency injection (and of a lot of other things)

The idea (in short) is that your service will know that it needs a IEntityDAO, and that someone will inject in it and implementation of the interface before actually using the service. That someone is called an IOC container (Inversion of Control container). It can be Spring, and what it does is usually described by an application configuration file and will be done at application startup.

Important Note: The concept is brilliant and powerful but dead simple stupid. You can also use the Inversion of Control architectural pattern without a framework with a very simple implementation consisting in a large static method "assembling" your application parts. But in an industrial context it's better to have a framework which will allow to inject other things like database connection, web service stub clients, JMS queues, etc...

Benefits:

  • Your have an easy time mocking and testing, as the only thing a class depends on is interfaces
  • You have a single file of a small set of XML files that describe the whole structure of your application, which is really handy when your application grows.
  • It's a very widely adopted standard and well - known by many java developers.

Sample java code:

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;
    }
}

And in spring configuration file, you will have something like that:

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

[...]

<bean id="ProductService" class="com.company.service.ProductService">
    <property name="entityDAO" ref="ProductDAO"/>
</bean>
Samuel Rossille
  • 18,940
  • 18
  • 62
  • 90
  • CDI is a bit more of a standard nowadays. EE 6 has changed much. – atamanroman Nov 05 '12 at 23:34
  • Thanks for the answer, it looks really good. Unfortunatly this is for some school project. It's not really relevant to the question, and the guy I work with already knows Spring. He asked the teacher if we could use it but he said no (cause we haven't handled it in lessons yet). I think I'll just keep them loosely coupled, then :) and assign the dao object in each service's constructor. – MarioDS Nov 06 '12 at 07:42
  • @MarioDeSchaepmeester Welcome to the real world. Sometimes for good or bad reasons you cannot take advantage of a framework or a library, but like I said in the "Important Note", you don't need spring to implement IOC. Actually if you just have a couple of classes using Spring would just be a waste of time. You can just set up your classes and layers, and pro grammatically instantiate them and link them together with setEntityDAO()-like methods. But probably IOC will be one of your courses later... Otherwise make sure to learn it on your own because it's a very important concept. – Samuel Rossille Nov 06 '12 at 14:15
  • @SamuelRossille I'm afraid that hoping to still see IOC this year would be too optimistic. I cannot begin to explain how shallow the courses are that my school gives, and I feel really disappointed. This is my last year and lessons are finished in January, with a project and an internship following. Good thing there's Stack Overflow and people like you to help me learn the important stuff. Would you think CDI is a good way to go from here? [I found a source that looks good](http://code.google.com/p/jee6-cdi/wiki/DependencyInjectionAnIntroductoryTutorial_Part1) – MarioDS Nov 06 '12 at 14:21
  • @MarioDeSchaepmeester That might be sad, but if you plan to make a career in software edition you will have to learn a lot on your own all the time anyways. I don't know CDI, I just discovered it thanks to atamanroman's comment, so I can't give advice about it. However it's never a bad thing to read about something. – Samuel Rossille Nov 06 '12 at 14:30
  • @SamuelRossille I don't mind to learn by myself :) but that's because I'm passionate about application development, or at least I've become passionate about it. Over time I have seen that learning thing by myself is really important, but the school should give more _pointers_ at least to important sources. – MarioDS Nov 06 '12 at 14:34