How to properly reuse business rules using Ejbs?

Asked

Viewed 702 times

4

I am refactoring a system where the greatest concern is to decrease the coupling and complexity of the various levels of inheritance, so the examples are illustrative.

I have the entities Contrato, ContratoUso and ContratoAdesao. I have one more Session bean ContratoRepository with the entity’s business rules Contrato.

The business rules of the most specialized contracts have much of the business rules of the Contrato.

How best to implement this?

I initially thought of some possibilities:

Inheritance

The ContratoUsoRepository and the rest inherit the rules of ContratoRepository and implement their specifications.

Example using Generics:

ContratoRepository<M extends Contrato> {
  recuperarContrato(int id) {
    return M;
  }
}

ContratoUsoRepository extends ContratoRepository<ContratoUSO>() {
  //métodos específicos de ContratoUSO
}

Delegation

Use composition, having ContratoRepository injected into ContratoUsoRepository and delegating to contract what is common?

Example with dependency injection:

ContratoUsoRepository {

  @EJB
  ContratoRepository contratoRepository;

  recuperarContrato(Int id){
     return contratoRepository.recuperarContrato(id);
  }

}

Example :

in the matter of my problem the business methods has the same behavior only changes the specific entity of return, for ex:

pesquisarContratoPorPeriodo(Date inicio,Date fim);

I can easily inherit this method for any contract, because the behavior is the same, only changes the type of contract returned.

or still it is preferable to delegate ? even not doing any additional tasks. delegate would simply:

contratoAdesaoService{
     @EJB contratoService
    pesquisarContratoAdesaoPorPeriodo(date inicio,Date fim){
          return contratoService.pesquisarContratoAdesaoPorPeriodo(inicio,fim);
}
  • 1

    Java is not my thing and I don’t know if I understand the question, but look if these questions here help you: http://answall.com/questions/11594/%C3%89-wrong-use-Heran%C3%A7a-of-classes-to-group-behaviors-and attributes-common, http://answall.com/questions/11378/%C3%89-correct-give-greater-prefer%C3%Aancia-a-composi%C3%A7%C3%A3o-do-que-Heran%C3%A7a

  • 1

    Bruno, I edited your question to try to improve it. Please, if something did not agree with your original intention, you can edit it again. Hug.

  • Thank you, that’s exactly the question.

  • 1

    Personally I recommend inheritance, for being more traditional. I do not have a very strong technical argument, just for traditionalism, and for another, it is easier someday to change the notes for injection than to change the way the inheritance is performed (rsrsr).

  • 1

    The details presented are insufficient for a good decision. By default, I avoid inheritance until it proves necessary. And then I keep avoiding hehehe. Inheritance adds complexity and compromises abstraction - it’s usually worth spending more time looking for a simpler solution. By the way, however detailed this may be, it tends to be a long discussion where no answer will be better than the other (except of course some simple answers that will surely arise). I believe this is an off topic question for Sopt.

1 answer

3


Basically, the two questions linked by @bfavaretto would already answer your question regarding class modeling. They are:

However, you can specifically analyze your case from the point of view of a Use Case or EJB architecture.

Use Cases

Use Cases of an Application can inherit other Use Cases. This includes the execution of certain business rules of the inherited use case. This is common in systems modeling.

However, inheritance in Use Cases does not exactly function as inheritance in object orientation. It consists of inserting additional steps in the Main Use Case.

In practice, this does not dictate that you need to necessarily use inheritance in the classes that implement these use cases. There are several techniques to create extension points in your code.

Enterprise Java Beans

I would not recommend using inheritance in Ejbs classes. These classes have a working contract with container. With inheritance you can end up in complicated situations where it is difficult to know if some detail should or should not be inherited. This without counting possible problems with annotations, transactions and visibility of access to the elements.

Delegation

My suggestion is that the inheritance of classes of business rules be avoided to the maximum. Using delegation allows you to reuse business rules where necessary without the need for class hierarchy.

Avoid coupling

Preferably, make your methods of business rules have low coupling to be reused more.

For example, instead of a method that assumes several things and access the bank to do a validation like this:

public void validarContrato(int idContrato) {
    Contrato contrato = contratoRepository.find(idContrato);
    if (contrato.hasErrors()) {
        throw new RuntimeException("Contrato inválido");
    }
}

You could receive an object Contrato:

public void validarContrato(Contrato contrato) {
    if (contrato.hasErrors()) {
        throw new RuntimeException("Contrato inválido");
    }
}

This way, you can validate contracts before you put them in the database. This is very useful for making unit tests and displaying errors to the user before registering something in the database.

Extension Points using Interfaces

One of the ways I consider most productive to implement extension points in use cases is to create an interface that works as a callback. In Java 8 you can use Amble to do this, however I will do using the traditional mode for illustration.

Imagine you have a use case as follows:

public void criarContrato(Contrato c) {
    recalcularContrato(c);
    validarContrato(c);
    //algo específico aqui
    gravarContrato(c);
}

If you want to put some step there that varies according to the situation, you can add a parameter that works as an extension point.

For this you will need an interface like the following:

public interface ExtensaoContrato {
    executar(Contrato c);
}

Then you can change the method as follows:

public void criarContrato(Contrato c, ExtensaoContrato pontoExtensao) {
    recalcularContrato(c);
    validarContrato(c);
    if (pontoExtensao != null) pontoExtensao.executar(c);
    gravarContrato(c);
}

This works more or less like the Strategy Pattern. The idea is that you leave a step to be provided by the client that will call the method, there may be as many implementations are needed from the interface.

So the method that calls the creation of the contract can do as follows:

criarContrato(contrato, new ExtensaoContrato() {
        public void executar(Contrato c) {
            //faz algo depois da validação e antes de gravar
        }
    });

The above code executes the method criarContrato passing the contract and also an anonymous class that implements ExtensaoContrato. The method executar, implemented in this anonymous class, will then be executed by the method criarContrato.

So you can "inject" any code there, in situations where you have a General Use Case and just need to do something specific at one or more points.

In the case of this question, one of the scenarios (depending on how the actual implementation is) is to have an implementation for each type of contract.

Simple delegation

Another option is to make the delegation simple, as already described in your question. If there are not many variations and inheritances is the right choice as it is simple and straightforward.

Final considerations

One of the most common errors, especially of those who are at an intermediate level in development, is to try to apply patterns and class hierarchies unnecessarily in the code.

That’s not all bad. It means the developer is maturing. However, the weak point of every pattern and inheritance is to greatly increase the complexity of the code. It is difficult to measure, but it would be necessary to consider whether this additional complexity brings more benefits than harm to the class model.

  • Very nice your answer, you added a lot, I will give a study on this question of Extension Points using Interfaces It seems very useful in some cases, as well as sophisticated. I edited my question , if possible confirm that this last example I gave (which is my context in some situations) delegate is still the best option. thank you.

  • @Brunoserqueira If a single repository implementation is able to handle all types of contract, you don’t need inheritance. Can have a single class with methods Generic: https://docs.oracle.com/javase/tutorial/extra/generics/methods.html

  • I meant that the common methods have the same behavior, without anything additional, but they also have their specific behaviors.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.