nzapponi
nzapponi

Reputation: 476

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

I am new to Java and I am coding up a modular application made like this:

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

Essentially, I want to be able to define an API with N classes, and then have a "Data Handler" module deal with storing the objects somewhere (a database, for example), without the front-end needing to know anything of how that is implemented.

So, let's say I have two classes defined in my API: Contract and Company. I want the front-end to be able to do something like:

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

This way, in the future I could change the way I store the data (the Data Handler module), without changing any code in the front-end.

To do this, I wrote two interfaces for Contract and Company in the API module. Then, in the data handler module I wrote to classes which implement the two interfaces: DbContract and DbCompany.

Now, I am running into issues because I have defined the getter/setter methods in the Contract interface as:

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

And implemented them in DbContract as:

public class DbContract implements Contract {
    private DbCompany company;

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

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

However, I am getting class type mismatch errors all over the place... Am I completely missing the point? How should I actually do this?

Thanks in advance for your help.

Upvotes: 4

Views: 120

Answers (2)

Thomas
Thomas

Reputation: 88707

myContract = new Contract();

This wouldn't work since you can't create instances of an interface.

You seem to have the right idea, but there also seems to be a misconception on the term "implementation".

If the frontend needs to create instances of those interfaces, it needs to know an implementation or provide its own. On the other hand if the frontend should not know about the implementations at all it should call the backend to create a new instance.

Besides that it might be a better design to make Contract and Company data containers and move the actual logic for saving to a service, e.g. your code would look like this:

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

Creating a new contract:

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

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

You could look up the service or let it be injected. For the latter have a look at Spring dependency injection.

Update:

In your comment you state that Company and Contract would be JPA entities and if I understand you correctly you don't want the frontend to have any notion that JPA is being used.

In that case you have two options:

  1. Make your objects plain POJOs and add an XML for the JPA-mapping in the backend. Then you'd treat every instance that is passed from the frontend as a detached entity.

  2. If you want to use annotations for the mapping and don't want the frontend to know about that you'd need to provide an intermediate layer (called data transfer objects = DTO) that is used by the API. Internally the backend would then translate between entities and DTOs.

Upvotes: 1

redge
redge

Reputation: 1182

Change

    private DbCompany company;

To

    private Company company;

And every thing should be sweet.

Otherwise you will need the front end to know what type of company you are dealing with and go generic. This has not been compiled But something like:

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

Upvotes: 2

Related Questions