Demonstrando o uso de encapsulamento ao facilitar o uso do componente rich:tree do Richfaces 02/08/2009
Posted by fredericobenevides in JSF, Seam.trackback
Quando começamos a programar em java, muitas pessoas ensinam que para criar uma classe encapsulada é apenas colocar os seus atributos como private e criar getters/setters para cada um deles. Geralmente, essas pessoas no início não aprendem que encapsulamento é aquele objeto que provê operações públicas ocultando suas implementações internas, que não precisam ser conhecidas por quem usa. Um exemplo real disso, é uma pessoa utilizar um carro conhecendo apenas as suas “operações” externas (volante, acelerador, marcha, etc…) sem ter necessidade de conhecer o seu funcionamento interno.
Então, eu resolvi criar um post pra demonstrar o uso de encapsulamento ao criar uma classe que facilitará na criação de árvores.
Como criar uma árvore usando RichFaces
Para quem não conhece o funcionamento do componente rich:tree, darei breves explicações de como utilizá-lo. Essas implementações foram feitas usando o framework Seam.
Os códigos abaixo terão sempre o mesmo resultado na geração da seguinte árvore:

Para criar uma árvore, utilizamos o TreeNodeImpl. Cada nó da árvore devemos setar a descrição utilizando o método setData do TreeNodeImpl. É simples, porém ao adicionar cada filho de um nó, devemos preocupar com o seu identificador.
public TreeNode getArvore() {
/* Raiz */
TreeNode rootNode = new TreeNodeImpl();
/* adicionando o pai1 na raiz */
TreeNodeImpl pai1 = new TreeNodeImpl();
pai1.setData("Pai_1");
rootNode.addChild(0, pai1);
/* adicionando filho1 ao pai1 */
TreeNodeImpl filhoPai1 = new TreeNodeImpl();
filhoPai1.setData("Filho_1");
pai1.addChild(0, filhoPai1);
/* adicionando filho2 ao pai1 */
filhoPai1 = new TreeNodeImpl();
filhoPai1.setData("Filho_2");
pai1.addChild(1, filhoPai1);
/* adicionando o pai2 na raiz */
TreeNodeImpl pai2 = new TreeNodeImpl();
pai2.setData("Pai_2");
rootNode.addChild(1, pai2);
/* adicionando filho1 ao pai2 */
TreeNodeImpl filhoPai2 = new TreeNodeImpl();
filhoPai2.setData("Filho_1");
pai2.addChild(0, filhoPai2);
/* adicionando filho2 ao pai2 */
filhoPai2 = new TreeNodeImpl();
filhoPai2.setData("Filho_2");
pai2.addChild(1, filhoPai2);
/* adicionando filho3 ao pai2 */
filhoPai2 = new TreeNodeImpl();
filhoPai2.setData("Filho_3");
pai2.addChild(2, filhoPai2);
return rootNode;
}
A página contendo o componente rich:tree que chama a árvore.
<rich:tree style="width:300px" value="#{tree.arvore}" var="item">
<h:outputText value="#{item}"/>
</rich:tree>
Agora que já temos um conhecimento de como trabalhar com o componente, podemos ver que é até simples o uso, apesar de termos um pequeno trabalho ao adicionar cada filho. Logo, resolvi criar uma classe para auxiliar na construção do objeto que representa a árvore, e também para que o desenvolvedor não perdesse tempo em estudar como implementar essa construção. Afinal, quanto menor o trabalho do desenvolvedor em se preocupar com cada detalhe, mais ele agiliza o desenvolvimento.
A seguir a nova implementação usando a classe Tree para auxiliar na criação da árvore.
public class Tree<T> {
private boolean root;
private String description;
private T object;
private TreeNode<Tree<T>> treeNode;
private List<Tree<T>> childs = new ArrayList<Tree<T>>();
public Tree() {
treeNode = new TreeNodeImpl<Tree<T>>();
root = true;
}
public Tree(String description, T object) {
treeNode = new TreeNodeImpl<Tree<T>>();
this.object = object;
this.description = description;
treeNode.setData(this);
}
public void addChild(Tree<T> tree) {
childs.add(tree);
}
public TreeNode<Tree<T>> toTreeNode() {
int i = 0;
for (Tree<T> tree : childs) {
TreeNodeImpl<Tree<T>> nodeChild = (TreeNodeImpl<Tree<T>>) tree.toTreeNode();
treeNode.addChild(i, nodeChild);
i++;
}
return treeNode;
}
public boolean isRoot() {
return root;
}
public T getObject() {
return object;
}
public String getDescription() {
return description;
}
@Override
public String toString() {
return description;
}
}
public TreeNode<Tree<String>> getArvore() {
/* criando a raiz */
Tree<String> parentRoot = new Tree<String>();
/* adicionando o pai1 na raiz */
Tree<String> pai1 = new Tree<String>("Pai_1", null);
parentRoot.addChild(pai1);
/* adicionando filho1 ao pai1 */
Tree<String> filhoPai1 = new Tree<String>("Filho_1", null);
pai1.addChild(filhoPai1);
/* adicionando filho2 ao pai1 */
filhoPai1 = new Tree<String>("Filho_2", null);
pai1.addChild(filhoPai1);
/* adicionando o pai2 na raiz */
Tree<String> pai2 = new Tree<String>("Pai_2", null);
parentRoot.addChild(pai2);
/* adicionando filho1 ao pai1 */
Tree<String> filhoPai2 = new Tree<String>("Filho_1", null);
pai2.addChild(filhoPai2);
/* adicionando filho2 ao pai1 */
filhoPai2 = new Tree<String>("Filho_2", null);
pai2.addChild(filhoPai2);
/* adicionando filho3 ao pai1 */
filhoPai2 = new Tree<String>("Filho_3", null);
pai2.addChild(filhoPai2);
return parentRoot.toTreeNode();
}
Como podemos ver, o código ficou mais simples e mais limpo para a criação da árvore. Para adicionar cada filho não houve necessidade de preocupar com o identificar numérico. A codificaçao ficou mais simples, porém produtivo.
Os getters foram criado apenas onde houve necessidade. Caso também fosse permitido o acesso ao treeNode, quebraria o encapsulamento, pois o desenvolvedor poderia modificar seus dados, sendo que apenas a classe Tree é o responsável para modificar.
Por fim, a classe está bem encapsulada, já que o desenvolvedor não tem necessidade de conhecer o funcionamento interno, ele tem apenas que conhecer as suas operações públicas.
Cara muito obrigado pela explicação!!!!
Fiquei procurando na net uma luz exatamente pra esse problema!!!!
Olá André, muito obrigado pelo comentário. É bom saber que te ajudou e vai ajudar em vários projetos que precisar.
Abraços.
cara muitissimo obrigado …acho ate que vc deveria mandar sua explicação para aqueles fdp da exadel …mais uma vez obrigado …tudo de bom pra vc …
Olá Mario, muito obrigado pelo comentário! É bom saber que esse tópico está ajudando as pessoas a criarem mais fácil as árvores no richfaces…
tem como saber quantos filhos o pai tem?
tipo um size()…
Claro. Na classe tree, é só criar um método que retorna o size do ArrayList criado. Agora se precisar contar até os filhos, netos etc.. Você faz um loop pegando o size de cada um e pronto.