Qui est responsable ?

Introduction

Dans ce premier TD du semestre 3, nous avons développé un mini-bus à messages afin de en place notre environnement de travail et rappeler les notions de base de la COO. Pour cela nous avions la liste des fonctionnalités primaires que doit respecter un simple système de bus à messages, mais aussi un scénario, ce qui permet d'accompagner l'étude de cas. Les instructions sont toujours concises : analyser le sujet, établir un modèle de conception puis le mettre en œuvre sous forme de développement.

Notions

  • Bus à messages : Outil permettant un transfert d'information entre deux acteurs du système de communication. Souvent représenté par des flèches, le message (flux) part d'un acteur source pour aboutir à un acteur de finalité.

  • Scénario : Description détaillé mais non exhaustive des possibilités d'un système suisvant un ordre chronologique par le bisais d'une mise en situation.

  • Modèle de conception : Ensemble des documents décrivant la conception d'un système tel que schémas, écrits, diagrammes. L'ensemble doit être cohérent et complet afin d'aboutir à la programmation.

Étude de cas

Description initiale : Le bus à messages

Un bus à messages permet à un “producteur” d'envoyer un “message”(texte, contenu multimedia …) vers des consommateurs. Les consommateurs peuvent lire les messages quand ils le veulent. Selon les modèles de bus, les consommateurs sont notifiés immédiatement du message (Twitter par exemple), ou bien doivent aller eux-même chercher leurs messages (Courriel par exemple).

Il existe beaucoup de modèles de “bus” : choix des consommateurs par filtrage sur le message, abonnement des consommateurs à des boîtes spécialisées, envoi des messages à la demande des consommateurs, dés qu'un message est lu, il n'est plus accessible aux autres consommateurs… Ces modèles d'architectures sont très utilisés pour faciliter des communications asynchrones et l'envoi d'informations à un groupe de destinataires (pensez au principe des tags sous Twitter par exemple).

De plus, nous avions des recommandations quant aux fonctionnalité auxquelles devait répondre le système :

  • Un agent peut créer un bus.
  • Des producteurs émettent des messages vers un bus.
  • Des consommateurs demandent à lire des messages sur le bus.
  • Un agent peut effacer des messages sur le bus.
  • Un consommateur peut demander à lire des messages et qu'il n'y en ait aucun.

Modèle préliminaire

Lors de l’analyse du sujet, nous avons premièrement et rapidement établi les 4 classes prédominantes du système, à savoir : Le GestionnaireBus, le Bus, la Boite et le Message, chaque classe étant un collecteur de la prochaine : le gestionnaire de bus représentais une liste de bus, le bus était une liste nommé de boites et chaque boite pouvant contenir plusieurs messages.

Modèle préliminaire : le bus à messages.


À noter : attention à ne pas garder la double visualisation des attributs lors d'une génération automatique, cela rend la lecture plus difficile.


Identification des attributs

Les attributs d'une classe sont définis par les propriétés de l'objet modélisé. L'ensemble de ses attribut représente sont état. Il suffit donc de s'interroger sur les possibilités du système afin d'en ressortir chaque propriété. En l'occurence notre système respecte le fondement suivant :

  • Un Message est défini par son contenu et sa date.
  • Une Boite est représenté par son nom (d’identification : il doit être unique et sert à l’identifier dans le système, il n’y a pas d’ID) et sa liste de Messages qu’il contient.
  • Il en va de même pour le Bus : son nom (toujours d’identification) et la liste de Boites qu’il contient.
  • Enfin, le GestionnaireBus est instancié une seule fois dans le système, il ne contient donc que la liste des Bus.

Passer la souris sur un des attributs pour voir le résultat en Java


Les attributs définis pour le système de bus à message sont attachés à une instance particulière. La classe définit le nombre et le type des attributs ainsi que les instructions de traitement attachées à des opérations, mais la valeur de chaque attribut et l’exécution des opérations restent attachées à un objet donné, instance de cette classe. Néanmoins, il est parfois utile de pouvoir représenter un attribut dont la valeur est partagée par toutes les instances d’une classe, de même qu’il peut y avoir des méthodes dont l’exécution est indépendante de tout objet. Ces membres particuliers sont appelés attributs ou méthodes de classe par opposition aux attributs ou méthodes d’instance.

Chaque objet encapsule une variable distincte (dont la valeur est propre à cet objet).

Une unique variable attachée à la classe, “partagée” par toutes les instances de la classe.


Identification des méthodes

Elles ont bien-sur été définis à l’aide du sujet en répondant aux questions posés. Il s’agissait notamment de question de responsabilité. Très important : une classe ne doit avoir qu’une responsabilité unique, car elle ne peux avoir qu’une unique raison d’être modifié. Cela permet de réduire les dépendances entre les différentes fonctions majeures qui compose une application afin d’augmenter le potentiel de réutilisabilité du code. À une question de responsabilité, nous devons donc répondre par une seule possibilité.

Par exemple, la question « qui est responsable de retrouver un bus à partir de son nom ? » nous fait d’abord poser une première question : retrouver un bus (parmi les autres) implique à celui qui retrouvera le bus de connaitre tout les bus existants.
Donc cette méthode retrouverBus(unNomBus (devenu getBus(unNomBus) : Bus) doit se retrouver dans une classe responsable des Bus. Celle classe sera donc capable (et ce doit être la seule) d’avoir une incidence sur celle-ci : elle pourra après avoir retrouvé le Bus le modifier ou détruire. Le GestionnaireBus est donc là pour ça, c’est à lui d’avoir la méthode getBus.

Après avoir établi la liste des méthodes que contiennent chaque classe et s’être penché sur la question de responsabilité, à savoir qui à le droit de faire quoi, nous sommes parvenu au modèle que vous trouverez ci-dessous. Nous nous sommes également occupé du contrôleur et avons intégré la classe UI, permettant de rapidement obtenir une interface en ligne de commande. Dans ce modèle nous pouvons très clairement identifier le pattern MVC, avec respectivement le GestionnaireBus, l’UI et le Controller.

Notre système : le bus à messages.


À noter : le contrôleur n'a pas le droit de modifier la partie métier sans passer par des objets métiers. Par exemple, il n'est pas autorisé à stocker la liste des bus.

Diagramme de séquence


Ce diagramme de séquence illustre la responsabilité de chaque partie du système. C’est l’agent qui déclenche une action voulant créer un bus via l’IHM, celle-ci communique l’information au Controlleur (qui s’écrit normalement Contrôleur) qui fait appel à un Objet de type GestionnaireBus. Le Gestionnaire de Bus a la responsabilité de créer un objet de la classe Bus puis l’ajoute à son attribut bus[]. Dans notre système, la classe GestionnaireBus à la responsabilité de créer un objet de la classe Bus qui elle a la responsabilité de créer un objet Boite. Enfin, la Boite est elle-même responsable de créer un objet de la classe Message. Ici, la classe GestionnaireBus à été désignée pour gérer plus facilement le contrôle. Elle représente notre système global.

À noter : généralement, l’objet responsable de la création d’un autre objet est celui qui va contenir, mettre en mémoire l’objet créé, posséder les informations nécessaires pour l'instancier. L’affectation de responsabilité est assez intuitive quand on en a l’habitude.