Briefly I would define as follows: badly made class design :), the constructor argument of Menu
should also be typed, since BdApp
is a raw type, in addition to which it could be a reference to IDAO
, nay BdApp
.
Why didn’t he prompt us to do it this way: private BdApp<Contato> bd = new BdApp<Contato>();
?
The way this code is, it doesn’t really make much difference to initialize in the declaration or constructor, one way or another at the end it only makes sense to assign BdApp<Contato>
or the attribute bd
in Menu
do not depend on anything of the generic type (which leads us to believe that it did not need to be generic). For example:
final BdApp<Integer> bd = new BdApp<>();
final Menu menu = new Menu(bd);
menu.listar();
This example above compiles and runs smoothly, but it doesn’t make any sense to how the class design is. As it stands, the attribute is typed (private BdApp<Contato> bd
), then even when building an instance of Menu
i tried to change the type of generic could have problems, according to which it was used later in the code.
In addition, the advantage of having assignment per constructor, Setter, etc. is that who instantncia defines the concrete type, be able to exchange implementations, change implementation in Runtime (with Setter, for example), etc.
However this is quite common, see the example below:
public abstract class Menu<T> {
private final IDAO<T> bd;
public Menu(final IDAO<T> bd) {
this.bd = bd;
}
public void cadastrar() {
try(final Scanner sc = new Scanner(System.in)) {
bd.add(this.instance(sc));
}
}
protected abstract T instance(final Scanner sc);
public void listar() {
final List<T> lista = bd.listar();
for (final T t : lista) {
this.imprimir(t);;
}
}
protected abstract void imprimir(final T t);
}
public class MenuContato extends Menu<Contato> {
public MenuContato(final IDAO<Contato> bd) {
super(bd);
}
@Override
protected Contato instance(final Scanner sc) {
final Contato contato = new Contato();
System.out.print("Digite o nome: ");
contato.setNome(sc.next());
System.out.print("Digite o cpf: ");
contato.setCpf(sc.next());
return contato;
}
@Override
protected void imprimir(final Contato t) {
System.out.println(t.getNome());
}
}
See what we make Menu
also generic, so we could have Menu of anything. Besides (and one of the better parts of this) is that we can change the implementation of IDAO
, as stated above. That is, we can pass an instance that saves the data in a list, one that uses BD persistence, etc., without needing to change absolutely anything.
And if it weren’t for the parameterized class the composition would look like this?
Yeah, if it’s not a generic type it wouldn’t have to parameterize it, then it would be like you yourself observed, just private BdApp bd
;
Probably this code is not yours, but follow some observations, in addition to the points cited above:
- consider always having the reference not to the concrete type, but to the interface, this gives you greater flexibility. Ie,
private BdApp<Contato> bd = new BdApp<>();
in place of private BdApp<Contato> bd = new BdApp<Contato>();
, private List<T> lst = new ArrayList<>();
in place of ArrayList<T> lst = new ArrayList<T>();
and so on. See more;
- from Java 7 there is the diamond operator, then you do not need to qualify the concrete type to instantiate the object, it will be inferred by the reference, ie,
private List<T> lst = new ArrayList<>();
and not private List<T> lst = new ArrayList<T>();
;
I quoted some Smells of the code just to notice how much he seems to be in trouble =)
Funny that I’ve tried to do something like
Arraylist
several times (unsuccessful, of course), but I resolved instantiating inside the builder, instead of going for clarifications as you did kkk– user28595