Spécifications d'ensembles d'entités


o EntitySpec
Cette classe permet de spécifier un ensemble d'entités, c'est-à-dire de définir cet ensemble sans en expliciter les éléments a priori.
L'invocation de sa méthode prédéfinie dite d'expansion (Expand) permet de générer de façon dynamique l'ensemble d'entités correspondant à la spécification dans le contexte courant. Les éléments de la liste générée seront nécessairement des instances, directes ou indirectes, d'une même sous-classe de Entity, appelée ici classe de référence. Pour que la liste générée contienne des entités de différentes classes, la classe de référence doit en être une sur-classe commune.
L'utilisateur crée une instance de EntitySpec pour chaque spécification différente dans son domaine. Cette instance porte alors la spécification. Il peut aussi créer une sous-classe EntitySpec, et coder dans son constructeur la spécification. Il suffit alors d'instancier la sous-classe, par un simple appel au constructeur. Les constructeurs des sous-classes seront placées, typiquement, dans UserEntitySpec.cc.

Trois manières de spécifier un ensemble d'entités

La définition de l'ensemble d'entités est donnée par l'utilisateur sous l'une des trois formes suivantes, mutuellement exclusives et liées à deux valeurs différentes du mode de la spécification.

Un premier complément de la spécification d'un ensemble d'entités est l'entité de référence. En effet, on peut vouloir sélectionner parmi les instances de la classe de référence, celles qui ont un certain lien fonctionnel ou structurel avec une autre, appelée l'entité de référence. Le moteur de DIESE passe cette information au prédicat de sélection ou à la fonction de construction sous la forme d'un argument prédéfini, de type Entity bien entendu.

Un second complément sont les spécifications de domaines de valeurs (voir la classe DescValueSpec à la page 'La classe de base des spécifications de domaines de valeurs'). L'utilisateur ajoute des spécifications de domaines de valeurs à la spécification d'entités en invoquant la méthode AddDescValueSpec.

Les étapes du codage

Les éléments de code qui permettent la sélection ou la création d'entités sur la base d'une spécification sont les suivants. Dans cet exemple, on s'intéresse à des instances de la classe A_CLASS.

  1. L'éventuelle création d'un domaine de valeurs pour un ou plusieurs descripteurs de A_CLASS. Avec la ligne suivante, on impose que le descripteur de symbole DESC_1 ait sa valeur à l'intérieur (IN) de l'intervalle [1 5] :
    DescIntValueSpec* mySelectorDomain = new DescIntValueSpec(DESC_1, IN, 1, 5);
    

  2. L'éventuelle création d'une fonction de sélection (dans le cas d'une sélection d'entités existantes) ou d'une fonction de construction (pour des instances qui n'existent pas encore). On place cette fonction dans UserEntitySpec.cc. Dans le code ci-dessous, on sélectionne les entités qui, en plus de satisfaire d'éventuelles contraintes spécifiées comme ci-dessus, ont 1 comme valeur du descripteur de symbole DESC_2, en excluant une instance désignée, passée en argument :
    bool mySelectorPredicate(EntitySpecMethod* pM) {
      Entity* pEref = pM->GetEntityArgValue(REFERENCEENTITY_ARGUMENT);
      Entity* pE = pM->GetEntityArgValue(CANDIDATEENTITY_ARGUMENT);
      if((pE->GetIntValue(DESC_2) == 1)
         &&
         (pE != pEref))
        return TRUE;
      else
        return FALSE;
    }
    

    Noter que cette fonction est le corps d'une méthode EntitySelector (sous-classe de EntitySpecMethod) dont une instance est un descripteur fonctionnel de la classe EntitySpec.

  3. La création d'une instance de EntitySpec, en précisant la classe de référence, celle des entités renvoyées :
      EntitySpec pES = new EntitySpec(A_CLASS);
    

  4. L'éventuel attachement des domaines de valeurs et/ou de la fonction (de sélection ou de construction) créés :
      pES->AssignSelectorPredicate(mySelectorPredicate);
      pES->AddDescValueSpec(mySelectorDomain);
    

  5. La sélection, puis la récupération du résultat s'opèrent par :
      Entity* pEref = GetNamedEntity(A_CLASS, "aClass_245");
      pES->SetEntityArgValue(ENTITY_SELECTOR, REFERENCEENTITY_ARGUMENT, pEref);
      pES->Expand();
      pEntityTab* result = pES->GetExpansion();
      Entity* pE_0 = result->get_nth(0);
      int val1 = pE_0->GetIntValue(DESC_1);
      int val2 = pE_0->GetIntValue(DESC_2);
      printf("\npour '%s' DESC_1 = %d DESC_2 = %d", pE_0->InstanceName(), val1, val2);
    
    >>
    pour 'aClass_247' DESC_1 = 4 DESC_2 = 1
    

    Noter qu'un corps n'a pas été donné à la méthode QuantityEvaluator, fixant un nombre maximum. On sélectionne donc toutes les entités satisfaisant la spécification.

Spécifications alternatives

Soit la fonction suivante de détermination du nombre maximum d'instances a créer ou sélectionner :

int myQuantityEvaluator(EntitySpecMethod* pM) {
  int result;
  ... // valuation du nombre requis maximum
  return result;
}

Exemple de fonction d'instanciation :

  EntitySpec pES = new EntitySpec(A_CLASS);
  pES->AssignEntityInstantiator(myEntityInstantiator);

BasicEntity* myEntityInstantiator(EntitySpecMethod* pM) {
  Entity* result;
  Entity* pEref = pM->GetEntityArgValue(REFERENCEENTITY_ARGUMENT);
  UserClassId id = pM->GetIntArgValue(CLASSID_ARGUMENT);

  result = App_NewEntityFromID(id);
  result->SetIntVarValue(DESC_1, pEref->GetIntVarValue(DESC_1));
  return result;
}

Exemple de fonction de création de liste d'instances existantes :

  EntitySpec pES = new EntitySpec(A_CLASS);
  pES->AssignEntityListInstantiator(myEntityListInstantiator);
  pES->AssignQuantityEvaluator(myQuantityEvaluator);

pEntityTab* myEntityListInstantiator(EntitySpecMethod* pM) {
  EntitySpec* pES = pM->DescribedEntitySpec();
  pEntityTab* result = pES->GetExpansion();
  result->erase();
  //Entity* pEref = pM->GetEntityArgValue(REFERENCEENTITY_ARGUMENT);
  UserClassId id = pM->GetIntArgValue(CLASSID_ARGUMENT);
  int N = pM->GetIntArgValue(LISTSIZE_ARGUMENT);

  pEntityTab* instanceList = GetEntityList(id); // les instances existantes
  for(int k=0;k<N;k++) {
    Entity* pE_k = instanceList->get_nth(k);
    result->push_back(pE_k);
  }
  return result;
}

Dans ce code ci-dessus, la valeur passée par l'argument de symbole LISTSIZE_ARGUMENT a été établie par le moteur en invoquant la méthode QuantityEvaluator, puisqu'un corps lui a été donné ( par AssignQuantityEvaluator).

Exemple de fonction de création de liste de nouvelles instances :

  EntitySpec pES = new EntitySpec(A_CLASS);
  pES->AssignEntityListInstantiator(myEntityListInstantiator);
  pES->IntQuantity(3);

pEntityTab* myEntityListInstantiator(EntitySpecMethod* pM) {
  EntitySpec* pES = pM->DescribedEntitySpec();
  pEntityTab* result = pES->GetExpansion();
  result->erase();
  //Entity* pEref = pM->GetEntityArgValue(REFERENCEENTITY_ARGUMENT);
  UserClassId id = pM->GetIntArgValue(CLASSID_ARGUMENT);
  int N = pM->GetIntArgValue(LISTSIZE_ARGUMENT);

  for(int k=0;k<N;k++) {
    Entity* pE_k = App_NewEntityFromID(id);  // création nouvelle instance
    result->push_back(pE_k);
  }
  return result;
}

Dans le code ci-dessus, la valeur passée par l'argument de symbole LISTSIZE_ARGUMENT résulte du message IntQuantity adressé à pES, avec la valeur 3.

Note importante : dans les deux fonctions de création de liste, ci-dessus, on reconstruit la liste qui est le membre de la classe EntitySpec renvoyé par le service GetExpansion. Avant de la reconstruite, on prend soin de la vider (par erase).


This page was generated with the help of DOC++.