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.
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
– bfavaretto
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.
– utluiz
Thank you, that’s exactly the question.
– Bruno Serqueira
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).
– Cold
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.
– Caffé