L’affichage des composites en ASP.NET
Beaucoup de gens ont travaillé avec des composites. Ils s’avèrent en effet utiles pour déterminer des règles imbriquées, des catégories à plusieurs niveaux, des menus récursifs etc. Il est par contre difficile de les afficher en ASP.NET sans transformer le code en amas monstrueux de conditions. Voici donc l’approche qui, selon mon humble opinion, s’est avérée la plus simple et la plus facile à maintenir.
1) Définir notre composite
La première étape consiste à vérifier si le composite en est bien un. En effet, une erreur que je vois souvent est de considérer que l’extrémité du composite est nécessairement l’élément qui n’est plus une collection. Hors, dans plusieurs cas, la dernière collection contient d’autres types qui n’héritent pas du type abstrait, ou le font “de force”. Un exemple simple serait le cas suivant:
J’ai des boîtes de crayons, de différentes tailles. Ces boîtes, faites pour la revente, peuvent être empaquetés dans des boîtes pour les magasins, qui à leur tour peuvent être empaquetés pour le transport, et ainsi de suite. L’implémentation erronée dont je parle ressemblerait à ceci:
classe Boîte héritant de BoîteStratégie
collection BoîtesImbriquées de type BoîteStratégie
classe Crayon héritant de BoîteStratégie
Le type Crayon ne partage aucune logique avec la boîte, pourtant beaucoup auront tendance à penser que le Crayon est l’extrémité de la structure, résultant en de grandes difficultés à filtrer les types à l’affichage. Une meilleure structure serait la suivante:
classe Boîte héritant de BoîteStratégie
collection BoîtesImbriquées de type BoîteStratégie
classe BoîteDeCrayons héritant de BoîteStratégie
collection Crayons de type Crayon
Le type Crayon ne partage aucune logique avec la boîte, pourtant beaucoup auront tendance à penser que le Crayon est l’extrémité de la structure, résultant en de grandes difficultés à filtrer les types à l’affichage. Une meilleure structure serait la suivante:
classe Boîte héritant de BoîteStratégie
collection BoîtesImbriquées de type BoîteStratégie
classe BoîteDeCrayons héritant de BoîteStratégie
collection Crayons de type Crayon
Dans le premier cas on aurait été obligé, dans le contrôle affichant une catégorie, de supporter tous les types d’éléments.
Dans le deuxième cas, on a un contrôle qui ne fait qu’afficher (encadrer) une catégorie, et le deuxième contrôle gère l’affichage d’une liste de crayons. On peut ainsi afficher une structure d’arbre contenant des couleurs sur l’horizontale sans complexifier la structure.
2) Définir l’affichage désiré
Il n’y a pas de “silver bullets”, Brooks a raison, et cela s’applique à tous les niveaux. Il existe beaucoup de méthodes pour afficher des composites, et certains affichages très complexes, ou non-standards, peuvent demander une approche complètement différente. Je ne présenterai ici la solution la plus commune selon moi.
Pour donner une idée des différents affichages possible, voici quelques exemples:
- Une liste “flattened” des items du composite
- Une liste semblable à une table des matières
- Un arbre semblable à la TOC d’une aide en ligne
- Un arbre dont les nodes sont des titres et les feuilles sont des fiches
- Un arbre chargé sur demande avec AJAX (librairie pour C#)
etc.
Pour la solution à la présentation 1, un simple repeater fait l’affaire, couplé à une méthode récursive comme un visiteur ajoutant chaque objet à une collection ordonnée.
La solution du 5 serait (mais là il ne s’agit que d’une opinion) mieux implémentée en contrôle pur qu’en UserControl.
Toutes les autres solution sont implantables avec la solution proposée.
3) Implémenter les contrôles
Nous aurons besoin d’un minimum de deux contrôles (qu’il faudra évidemment renommer selon le cas précis d’implémentation):
- Un UserControl pour afficher le composite (pour afficher Boîte). Nommons-le CompositeView.ascx et faisons-le hériter de IStrategyView.
- Un UserControl pour afficher les extrémités (pour afficher BoîteDeCrayons). Nommons-le LeafView.ascx et faisons-le hériter de IStrategyView.
- Une interface IStrategyView n’affichant qu’une propriété lecture/écriture. Nommons-la IStrategyView.DisplayedStrategy.
- Plutôt que Boîte, Définissions les abstractions IStrategy représentant la classe abstraite dont hérite le composite, et Composite, assez auto-explicatif.
3.1) CompositeView.ascx
Ce contrôle ne contiendra que le conteneur parent. Un cas typique serait l’étiquette du composite, une forme d’indentation visuelle et un Repeater contenant les enfants.
CategoryName
<blockquote>
<asp:repeater
id=”ChildrenRepeater”
datasource=”<%#((CategoryComposite)DisplayedCategory).Children%>”
Runat=”server”
OnItemCreated=”ChildrenRepeater_ItemCreated”>
<itemtemplate />
</asp:repeater>
</blockquote>
Le code de cet affichage de composite contiendra principalement une méthode chargeant le bon contrôle-enfant dynamiquement:
protected void ChildrenRepeater_ItemCreated(…)
{
if(
e.Item.ItemType == ListItemType.Item ||
e.Item.ItemType == ListItemType.AlternatingItem
)
{
Control ctl = LoadControl(
e.Item.DataItem.GetType().Name + “View.ascx”
);
((ICompositeView)ctl).DisplayedCategory
= (IStrategy)e.Item.DataItem;
e.Item.Controls.Add(ctl);
}
}
Voilà, notre récursivité est prête. Il ne reste plus qu’à implémenter les feuilles.
3.2) LeafView.ascx
Ce contrôle est utilisable à toutes les saveurs. La seule restriction est d’implémenter l’interface IStrategyView et que le contrôle puisse s’intégrer au design du CompositeView.ascx. Un exemple relatif aux boîtes de crayon serait un Repeater qui afficherait une table à trois lignes dont la partie du haut et du bas seraient des images de mines et d’effaces de crayon, tandis que le centre serait rempli avec la couleur de Crayon.Couleur. Le Repeater itérerait en créant des colonnes pour chaque crayon.
Conclusion
Cette approche est, jusqu’ici, le juste milieux entre des approches simples mais peu flexibles, et d’autres très complexes à maintenir. Elle permet aussi d’être modifiée pour afficher différents types de contrôles selon des conditions variées. Le design est centralisé et ne contient aucune condition d’affichage, le rendant simple à maintenir. Elle n’a rien d’extraordinaire, pourtant j’aurai vu et fait beaucoup d’implémentations très originales pour afficher des composites, pas toujours très efficaces je l’avoue.