Generic System permet de persister des arbres. Pour commencer nous avons besoin de créer un arbre, puis de l’instancier. Une instance sans super est interprétée par Generic System comme la racine de l’arbre. Pour ajouter une feuille ou une branche à un nœud, il faut créer une instance de l’arbre en précisant ce nœud comme super.
Premier exemple
Tout développeur web connaît la structure de base d’une page web. Voyons comment créer un arbre HTML simple avec Generic System :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
Engine engine = new Engine(); // Create a tree called tags Generic tags = engine.addInstance("Tags"); // Create the root html Generic html = tags.addInstance("html"); // Create the children header, body and footer Generic head = tags.addInstance(html, "header"); Generic body = tags.addInstance(html, "body"); Generic foot = tags.addInstance(html, "footer"); // Create the children p and table for the node body tags.addInstance(body, "p"); tags.addInstance(body, "table"); // Persist changes engine.getCurrentCache().flush(); |
Deuxième exemple : relations d’un arbre avec un autre type
Complétons maintenant notre premier exemple avec la création d’un type Color auquel on ajoute trois instances de couleur :
1 2 3 4 5 6 7 |
// Create a new type color Generic color = engine.addInstance("Color"); // Add three new colors Generic blue = color.addInstance("blue"); Generic red = color.addInstance("red"); Generic green = color.addInstance("green"); |
Créons ensuite une relation tagsColor entre notre arbre Tag et notre type Color et ajoutons quelques liens :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// Create a relation between tag and color Generic tagsColor = tags.addRelation("TagsColor", color); // Add links tags.setHolder(tagsColor, "BlueDefault", blue); html.setHolder(tagsColor, "htmlRed", red); body.setHolder(tagsColor, "bodyGreen", green); assert tags.getHolders(tagsColor).first().getTargetComponent().equals(blue); assert html.getHolders(tagsColor).first().getTargetComponent().equals(red); assert head.getHolders(tagsColor).first().getTargetComponent().equals(red); assert body.getHolders(tagsColor).first().getTargetComponent().equals(green); assert p.getHolders(tagsColor).first().getTargetComponent().equals(green); // Persist changes engine.getCurrentCache().flush(); |
Voici une représentation schématique de l’arbre que nous venons de créer, qui met en évidence la relation et les links entre notre arbre et notre type :
Parcourir un arbre
Pour parcourir un arbre avec Generic System, le pattern Visitor a été prévu. Il suffit de faire appel à la méthode traverse sur le nœud à partir duquel on souhaite parcourir l’arbre. Comble du raffinement, il est possible de spécifier un traitement à effectuer avant et après le parcours de chaque nœud (pré- et post-fixé).
Reprenons notre premier exemple d’arbre représentant une page web, et parcourons-le pour afficher les nœuds avant et après qu’ils soient parcourus :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// Pass through the tree from html html.traverse(new Visitor() { @Override public void before(Generic node) { System.out.println("before : " + node.getValue()); } @Override public void after(Generic node) { System.out.println("after : " + node.getValue()); } }); // Persist changes engine.getCurrentCache().flush(); |
Exécutez ce code chez vous. Vous devriez avoir un résultat semblable à celui-ci :
1 2 3 4 5 6 7 8 9 10 11 12 |
before : html before : header after : header before : body before : p after : p before : table after : table after : body before : footer after : footer after : html |
Generic System n’est pas limité à des arbres à un seul parent. En fait, Generic System est un modèle de données généralisable, il n’est pas limité sur les arbres et permet la gestion d’arbres à n parents.
Arbres à n parents
Nous allons voir la notion d’arbres à n parents à travers un exemple. Je suppose que vous avez tous songé un jour à réaliser votre arbre généalogique ? Voilà l’occasion rêvée ! Commençons par créer notre arbre, puis les parents :
1 2 3 4 5 6 7 8 |
Engine engine = new Engine(); // Create a binary tree called GenTree Generic genealogicalTree = engine.addInstance("GenTree"); // Create the root father and mother Generic father = genealogicalTree.addInstance("father"); Generic mother = genealogicalTree.addInstance("mother"); |
Pour créer les enfants, nous avons besoin d’indiquer quels sont leurs parents. Pour cela, il suffit d’indiquer les parents lors de la création de l’instance (sous forme de List) :
1 2 3 |
// Create the children : a son and a daughter Generic son = genealogicalTree.addInstance(Arrays.asList(father, mother), "son"); Generic daughter = genealogicalTree.addInstance(Arrays.asList(father, mother), "daughter"); |
Nous pouvons ensuite vérifier que chaque parent a pour enfant les instances son et daughter :
1 2 3 4 5 6 7 8 |
// Get children of father assert father.getInheritings().containsAll(Arrays.asList(son, daughter)); // Get children of mother assert mother.getInheritings().containsAll(Arrays.asList(son, daughter)); // Persist changes engine.getCurrentCache().flush(); |
Vous voyez, rien de bien compliqué ! Voici la représentation schématique de notre arbre généalogique :
En résumé
- addInstance sans super ajoute une racine à un arbre.
- addInstance avec un ou plusieurs super ajoute un nœud à un arbre.
- La méthode traverse du pattern Visitor permet de parcourir un nœud de l’arbre.
- Les méthodes before(Generic node) et after(Generic node) permettent de définir les traitements respectivement avant et après le parcours de chaque nœud (parcours pré- et post-fixé).
Ce billet n’était pas vraiment complexe si vous avez l’habitude d’utiliser les arbres. Le seul point que vous ne connaissiez peut-être pas était la notion d’héritage dans les arbres.
Dans le prochain billet, nous aborderons une notion bien différente de ce que nous avons vu jusqu’ici mais Ô combien importante dans toute base de données : la gestion de la concurrence.