terça-feira, 15 de março de 2011

Arquitetura de Software: Quando usar a agregação e quando usar a herança?

Uma vez, eu falei da diferença de agregação, composição e herança.
Agora, vou tentar falar de quando se pode usar um ou outro. Parece fácil diferenciar, mas é muito mais complexo do que se imagina...

Por que eu digo isso?
Porque a própria API do Java SE contém erros de herança/agregação.

Verdade? Como assim?

Vejamos a classe Stack do pacote java.util:

public class Stack<T> extends Vector<T>{
....

public boolean empty() {
...
}

public T peek() {
...
}

public T pop() {
...
}

public T push(T item) {
...
}

public int search(Object o) {
...
}

}

Hum... Ela herda da classe Vector e os métodos parecem corretos para uma classe que representa uma pilha...

Mas existem alguns problemas...

E você me pergunta: Como assim??? Quais???

Vejamos, como Stack herda de Vector, os métodos que a classe Vector possui também existem na classe Stack, gerando o seguinte problema:

Se, em um Vector, eu posso remover um item de qualquer posição do vetor através do método remove(int i), e posso colocar o item em qualquer lugar através do método add(int i, E item), então eu posso fazer o mesmo em um Stack (pilha):

Stack<String> pilha = new Stack<String>();
pilha.push("Primeiro");
pilha.push("Segundo");
pilha.remove(0); //Remove o primeiro item colocado em uma pilha? Não deveria ser sempre o último colocado?
pilha.add(0,"Terceiro"); //Colocando o item abaixo do topo de uma pilha (???)

E isso não esta errado? Por definição, uma pilha deveria somente colocar ou retirar itens do topo? (pelo menos, eu acho que seria o esperado...)

Neste caso, parece que seria melhor usar uma agregação:

public class Stack<T> {

private Vector<T> v;

public Stack() {
v = new Vector<T>();
}

public boolean empty() {
return v.isEmpty();
}

public T peek() {
return v.lastElement();
}

public T pop() {
T t = peek();
v.remove(t);
return t;
}

public T push(T item) {
v.add(item);
return item;
}

public int search(Object o) {
return v.indexOf(o);
}

}

Assim, um Stack (pilha) não seria um Vector (vetor), a classe somente utilizaria um objeto Vector. (o que parece "certo"...)

Para usar herança, é preciso realmente saber se uma classe tem as mesmas caracteristicas de outra (por exemplo: Carro herda de Veiculo por que um Carro também é um Veiculo).
De resto, se você não tiver certeza, ou não souber, vale a dica: é uma agregação. :)

É díficil... mas se não fosse, não seria Orientação á Objetos. :P

Até, espero que isso ajude alguém!
Obs.: Esta dica é de um professor meu! Valeu! :)

Nenhum comentário: