What you’re saying is, pray you want it:
public interface IController<E> {
void adicionar(E Element);
...
}
And now this:
public interface IController<E> {
E adicionar(E Element);
...
}
It is not possible to vary the type of return in this way.
It is a common temptation to want to be too granular when defining an API. You would like each detail to accurately reflect the behavior of each object.
However, the more variation, the more complexity and in the vast majority of cases it is worth sacrificing the savings of one or two lines of code to achieve consistency.
Maintain consistency
The common solution for this specific case is to always return the object included. It is good practice because the object, after having the data included in the database usually gains a generated ID, timestamp or some other attribute generated at the time of insertion and which may be needed in the system.
Even though today you only see the need for a case, it tends to grow as the system evolves.
In cases where there is nothing to do, you can simply return the same object you received in the parameter:
@Override
public Entidade adicionar(Entidade entidade) {
//insere no banco
return entidade;
}
Perks:
- Costs nothing
- Consistent API (exceptions and behavior variations increase system complexity)
- Facilitates system maintenance
Disadvantages:
- One more line of code?
- I couldn’t think of anything concrete...
API granular
If, even with what I wrote above you still want to be granular, the solution is to define interfaces more granular.
Example:
interface IGeneralController<E> {
//...
}
interface IReturningAppenderController<E> {
E adicionar(E Element);
}
interface IAppenderController<E> {
void adicionar(E Element);
}
public class Controller implements IGeneralController<Entidade>, IReturningAppenderController<Entidade> {
@Override
public Entidade adicionar(Entidade entidade) {
//insere no banco
return entidade;
}
}
public class OtherController implements IGeneralController<Entidade>, IAppenderController<Entidade> {
@Override
public void adicionar(Entidade entidade) {
//insere no banco
}
}
It seems kind of cool, but now you have a more verbose code and a lot of conditions and Casts which you will have to do at runtime.
I thought about it, but then all controllers will have to return an object, because of a method in only one of them..
– user28595
But this is the idea of Interface no? Create a template for something that will have similar behavior/structure.
– Rubico
Equal, not similar, when it is only similar, needs another interface.
– Maniero
This Icontrollerespecial seems to be close to what I need, I’m going to test it here. (off-topic: it’s strange to see an interface being extended, even if both interfaces are hehe)
– user28595
Bigown, the problem is I only have 2 choices: either I force all controllers to keep returning NULL just so one of them returns something (which I wanted to avoid), or I adapt/isolate).
– user28595
It didn’t work, the IDE complains that the 2 add methods of the interfaces are in conflict. It seems that my way of thinking is not right for the problem, I’ll see what I can change.
– user28595
Read the answer, I edited it. But there’s no good solution to this but to change what you’re doing.
– Maniero
I don’t have the slightest clue how to handle it any other way. I cannot void this method because I need to display the data with the id that the bank saved it. You think it would be "Dirty Code" for me to make everyone return null just to fit in? There is no other way to return the id of the database, of the other fields of the returning object in the table, only the id is indexable and unique.
– user28595
I think. But I can’t talk without knowing the whole problem. Of course there are situations where the ideal is not possible. I think the whole concept of the application can be wrong :) When you start making the house pie, it doesn’t straighten anymore.
– Maniero
I agree with @bigown! You’re looking to assign two behaviors to the same interface. This makes the contract concept lose its meaning. What you can do is have 3 interfaces. One common to all, and two with the specific add() . So you would implement two of them. You can also segment interfaces by operation, edit, list, add. Still, as @bigown said, solving the syntax issue won’t free you from future problems if architecture brings you some problems.
– Danilo Gomes