Bonjour à tous,
Je rencontre une nouvelle difficulté pour modéliser ce que je souhaite... Et le livre sur les DSL n'aborde que très succintement mon problème (p.126 à 128, "More on Relationship derivation").
Grossièrement, j'aimerai pouvoir spécialiser mes relations entre concepts. Un exemple sera surement plus parlant...
Imaginons que je modélise deux concepts génériques
GenericClass et
GenericAttribute. Je place une embedded relation
GenericClassHasGenericAttributes entre les deux.
GenericClass possède 0..*
GenericAttributes dans la propriété nommée
Attributes;
GenericAttribute ne peut avoir que 0..1
GenericClass dans la propriété
Class.
Maintenant, je crée deux nouveaux concepts :
Class qui hérite de
GenericClass et
Attribute qui hérite de
GenericAttribute. Je veux pouvoir spécifier que ces concepts ont des contraintes supplémentaires dans leurs relations, ici, un concept
Class ne peut être relié qu'à un concept
Attribute.
Ce que je veux à tout pris garder, c'est au final n'avoir qu'une seule et même propriété pour l'ensemble des cas possibles : la propriété
Attributes dans le concept
Class et la propriété
Class dans le concept
Attribute. Leur contenu pouvant donc varier suivant le type des concepts mis en jeux.
Comment pourrais-je mettre en place cette contrainte dans les DSL?
---
J'ai actuellement une solution lors de l'utilisation d'une "reference relationship". Je vous la donne car :
1: Ce n'est peut être pas la meilleure méthode et dans ce cas, cela me permettra de lire vos remarques
2: Ca peut intéresser certaines personnes.
J'ai gardé l'exemple décrit plus haut, en remplaçant la relation "embedded" par une relation "reference".
Ensuite, j'ai modifié le "Connection Builders" accessible à partir du Dsl Explorer.
- Pour commencer, j'ai supprimer le
ClassReferencesAttributesBuilder. En effet, comme je vais le redéfinir plus tard, je n'en ai plus besoin.
- Ensuite, je rajoute dans le
GenericClassReferencesGenericAttributesBuilder un nouveau "Link Connect Directive" par clique droit.
Je sélectionne ce nouvel item pour l'éditer dans la fenêtre "DSL Details". J'indique dans le menu déroulant la relation
ClassReferencesAttributes. Puis, j'indique la source et la cible de cette relation : source =
Class et target =
Attribute.
- Grâce à ça, on peut contraindre maintenant pour une même connectionbuilder plusieurs comportements/contraintes suivant la source et/ou la cible de la relation.
J'ai maintenant deux items dans mon builder :
GenericClassReferencesGenericAttributes et
ClassReferencesAttributes. Je dois, pour obtenir le comportement souhaité, limiter la relation
GenericClassReferencesGenericAttributes car celle-ci permet de base à n'importe quelle
GenericClass (et ses classes dérivées telle que
Class!) de se relier à n'importe quelle
GenericAttribute (et donc
Attribute!). L'objectif est ici de contraindre une relation de type
GenericClass <-->
GenericAttribute OU
Class <-->
Attribute. La seconde relation ayant déjà été décrite dans l'item
ClassReferencesAttributes, il nous reste à définir la première.
Pour cela, j'ai selectionné l'item
GenericClassReferencesGenericAttributes et accédé à ses propriétés par la fenêtre "DSL Details".
J'ai coché la case "Custom accept" de la ligne
GenericClass dans l'onglet "Source role directives". Je dois alors déclarer mes propres fonctions dans la classe partielle GenericClassReferencesGenericAttributesBuilder :
partial class GenericClassReferencesGenericAttributesBuilder
{
private static bool CanAcceptGenericClassAsSource(GenericClass genericClass)
{
if (genericClass is Class)
return false;
return true;
}
private static bool CanAcceptGenericClassAndGenericAttributeAsSourceAndTarget(GenericClass genericClass, GenericAttribute genericAttribute)
{
if (genericClass is Class || genericAttribute is Attribute)
return false;
return true;
}
}
Au niveau modeleur, l'utilisateur ne peut maintenant relier que des GenericClass à des GenericAttribute et des Class à des Attribute. Et cela, sans utiliser plusieurs champs (
Attributes dans GenericClass et dérivés ;
Class dans GenericAttribute et dérivés) pour chacune de ces relations.
Ce qui me gène aujourd'*** dans cette solution est de devoir faire appel à du CustomCode... En gros, si le métamodèle change, il y'a de forte chance pour que je sois obligé de devoir modifier mon code pour l'adapter. J'aurai aimé une solution plus générique et automatique.
Je pourrai fournir ce projet correspondant dans la section appropriée du site.