Applying interface in Controllers

3

I have some controllers that call their respective models and would like to interface on them. I created an interface with some methods that would be important for everyone to implement, as follows:

public interface IController<E> {

    public void adicionar(E Element);

    public void editar(E element);

    public List<E> listar();

    public void excluir(E element);
}

E is the type of object that the controller handles. (Ex. UsuarioController will implement IController<Usuario> ).

Currently in the system, all controllers already have these interface methods. The problem is that in one of the controllers , the adicionar(E element) method needs to return the same object that was added, not void , because this object returns with the id registered in the database, then , I display the data of this object on screen.

Given the above, how can I apply an interface to classes with common behaviors (such as controllers ) and one of them has one of the different "contract" methods?

    
asked by anonymous 23.03.2016 / 13:25

3 answers

3

What you are saying is that sometimes you want this:

public interface IController<E> {
   void adicionar(E Element);
    ...
}

And pray this:

public interface IController<E> {
   E adicionar(E Element);
    ...
}

You can not vary the return type in this way.

It's a common temptation to want to be very granular when defining an API. You would like each detail to accurately reflect the behavior of each object.

But the more variation, more complexity, and in the vast majority of cases it's worth sacrificing the economy of one or two lines of code for consistency.

Maintain consistency

The common solution to this specific case is to always return the included object. It is a 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 that may be required in the system.

Even though you only see the need for a case today, 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;
}

Advantages:

  • It costs nothing
  • Consistent API (exceptions and behavior variations increase system complexity)
  • Facilitates system maintenance

Disadvantages:

  • One more line of code?
  • I could not think of anything concrete ...

Granular API

If, even with what I wrote above you still want to be granular, the solution is to define interfaces more granularly.

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 looks cool, but now you have more verbose code and a lot of conditions and casts you'll have to do at runtime.

    
24.03.2016 / 02:34
3

If I understood correctly it would be this:

public E adicionar(E Element);

Otherwise, you can not use the same interface. What could be inherited from this:

public interface IControllerEspecial<E> extends IController<E> {
    public E adicionar(E Element);
}

This does not completely solve the problem. The ideal would be a bigger gambiarra (which is sometimes necessary). You would have to create an interface without this adicionar method, then create that IController extending with this signed method returning void . Already the IControllerXXX would have the same method with signature returning E . The way I showed it would have two methods adicionar with different signatures.

Another way is to have completely separate interfaces, but then it starts to override the engine, because you start having to remember that you have to use the auxiliary interface. What happens if I use IController and forget to use helper only with the method that causes problems? Do you realize that this solution is spoiling the correct design to solve a specific problem? Suddenly you have a CRUD interface without C. It seems conceptually that this is wrong. The contract goes haywire.

Particularly I would try to change something to normalize operations. To always return the same thing is one of them. I do not know if it's the ideal for your case.

    
23.03.2016 / 13:27
1

Depending on your implementation you may use a different approach. Have a method with one void and another with the return of the object. It could have in your interface:

public interface IController<E> {

 public void adicionar(E Element);

 public void editar(E element);

 public List<E> listar();

 public void excluir(E element);

 public Element retornaElement();
//Se você controla os id's pode utiliza-lo como parâmetro. Caso não, caso sejam incrementais irá sempre buscar o último registro inserido.
}

You need to be aware of the competition, depending on your type of application for this operation. Another point of attention is to make sure that commit of the insert command in the database actually existed so that you can actually retrieve the last inserted record.

In this way, your implementation could be:

public Element implementacaoController(){
  // código 
  adicionar(element);
  // garantia de commit e conclusão da transação
  return retornaElement(); //aqui dependendo da sua implementação poderia passar o id do element, ou seja, element.getID(), ou simplesmente recuperar o último registro inserido.
}

If you have difficulties with the behavior of the method in insert and retrieve during the same execution. Try working with isolated methods being viewed through a third method.

Depending on your context, these approaches might suit your need. Hugs!

    
27.03.2016 / 17:32