Définition responsabilité

On définit la responsabilité d’un objet comme un ensemble de comportements dont il a l’obligation de réaliser (un contrat). On peut distinguer deux types de responsabilité pour un objet donné

La responsabilité de faire :

- faire quelque chose (un calcul, créer un autre objet)
- déclencher une action sur un autre objet
- contrôler et coordonner les activités d'un autre objet

La responsabilité de savoir :

- connaître les valeurs de ses propres attributs (données privées encapsulées)
- connaitre les objets qui lui sont rattachés
- connaître les éléments qu’il peut calculer ou dériver

Les principe G.R.A.S.P s’inspire de notre monde, nous les humains, et essaye de par ses comportements de s’approcher le plus du monde réel. On parle d’anthropomorphisme. Les principes se veulent rationnels en réduisant au maximum la distance entre les concepts réels et le modèle de conception. G.R.A.S.P étant composé d’un ensemble de principes, il se décompose en plusieurs méthodes ou « design patterns » chacun répondant à un problème spécifique, nous reviendrons sur la notion de design pattern dans la dernière partie du compte rendu

Information expert

La responsabilité est la notion fondamentale de G.R.A.S.P, si chaque objet possède une responsabilité il est nécessaire de la définir.
Problème :
Comment décider de la responsabilité des objets ?
Solution :
Il faut repérer la classe qui possède les informations nécessaires pour réaliser une responsabilité donnée. On appel cet objet l’expert en information (information expert), c’est l’objet le plus responsable pour assurer ce contrat.
Exemple :
Prenons l’exemple d’une boite de message étudiée dans le TD2. La boite de message possède un ensemble d’instances d’objets Message, cette classe est la seule à posséder les informations relatives aux messages. Grâce à ses informations découlent la méthode créerMessage() : la classe BoiteMsg aura la responsabilité de créer des instances de la classe Message.

Creator

Dans la programmation objet des instances d’objets seront créées lors de l’exécution système, cependant pour assurer une cohérence au niveau du modèle et pour assurer une cohérence avec le monde réel, tous les objets n’auront pas le droit de créer des instances de classe. Il faut donc choisir quels objets auront cette responsabilité.
Problème :
Comment décider si un objet à la responsabilité de créer une nouvelle instance d’une classe ?
Solution :
Affecter à la classe B la responsabilité de créer une instance de la classe A si une - ou plusieurs - des conditions est vraie :
- B contient ou agrège des objets A
- B enregistre des objets A
- B utilise étroitement des objets A
- B a les données d’initialisation qui seront transmises aux objets A lors de leur création
Si une de ce conditions est respectées on dit que B est un expert en ce qui concerne la création de A.
Exemple :
Prenons à nouveau l’exemple de la boite de message du TD2, une boite de message agrège des objets Message, c’est-à-dire que si la destruction de la boite de message implique la destruction des messages.

Controller

Un contrôleur est un objet qui a la responsabilité de recevoir et coordonner des événements majeurs du système. Il peut y avoir un ou plusieurs contrôleurs dans un modèle, dans le dernier cas, chaque contrôleur sera spécialisé. On distingue le contrôleur de l’IHM car le contrôleur fait le lien entre IHM et couche logicielle, il n’est pas en contact avec l’utilisateur contrairement à l’IHM. On distingue deux types de contrôleur :
- Controller façade : il représente tout le système à utiliser quand il y a peu d’événements systèmes sinon le controller serait trop chargé.
- Controller cas d’utilisation : il a la responsabilité de contrôler les événements relatifs à un cas d’utilisation plus optimal quand il y a beaucoup d’événements systèmes
Problème : Comment déterminer la classe qui à la responsabilité d’être controller ?
Solution : Il faut trouver ou créer une classe dans le modèle de conception qui correspond au critère suivant :
- elle représente le système global, un sous-système majeur, un équipement sur lequel le logiciel s’exécute (à des variantes d’un contrôleur Façade)
- elle représente un scénario de cas d’utilisation dans lequel l’événement système se produit
Exemple : Dans l’approfondissement du TD2 était demandé de réaliser un gestionnaire permettant de gérer les bus de message et tous les événements relatifs au problème. La classe gestionnaire fait ici office de Controller façade, il va coordonner tous les événements en rapport à la création et l’ajout de bus et messages. On remarque que même sur un problème de petit ordre de grandeur, ce gestionnaire possède déjà beaucoup de responsabilités d’où l’intérêt des controller cas d’utilisation

High Cohesion

La cohésion (la cohésion fonctionnelle) est une mesure de l’étroitesse des liens et de la spécialisation des responsabilités d’un élément (d’une classe). Une classe qui a des responsabilités étroitement liées et n’effectue pas un travail gigantesque est fortement cohésive. Cependant une forte cohésion peut être un obstacle à la réutilisabilité du code et donc au principe de faible couplage. De plus le principe de responsabilités étroitement liées peut rendre une classe plus complexe et moins concrète.
Problème :
Comment parvenir à maintenir la complexité gérable ? Comment s’assurer que les objets restent compréhensibles et faciles à gérer tout en contribuant au faible couplage ?
Solution :
Attribuer une responsabilité de telle sorte que la cohésion reste forte. Appliquer ce principe pour évaluer les solutions possibles.

Low Coupling

Le couplage représente le degré de dépendance entre deux classes. Une dépendance est un lien entre deux classes qui peut se créer de plusieurs façons : héritage, attribut, implémentation d’une interface, méthode. On dit que la classe A dépend de la classe B. Trop de dépendance entre des classes réduit la réutilisabilité du code.
Problème :
Comment réduire les dépendances et pallier à leurs problèmes ?
Solution :
Affecter une responsabilité de sorte que le couplage reste faible. Appliquer ce principe pour évaluer les solutions possibles

Polymorphisme

Le polymorphisme consiste à donner le même nom à des méthodes dans différents objets. Ainsi des méthodes de mêmes noms peuvent avoir des comportements différents ou manipuler des types différents.
Le polymorphisme se décompose en deux types majeurs :
-La surcharge qui permet d’implémenter de manières différentes une même méthode en changeant sa signature c’est-à-dire ses arguments (type ou nombre d’arguments).
-La redéfinition qui consiste à redéfinir une méthode de manière différentes tout en gardant la même signature (même nombre d’arguments et même type).
Problème :
Comment gérer des alternatives dépendantes des types ?
Comment créer des composants logiciels « enfichables » ?
Solution :
Quand des fonctions ou des comportements connexes varient en fonction du type (classe), affectez les responsabilités - en utilisant des opérations polymorphes - aux types pour lesquels le comportement varie
Exemple :
Dans le TD7 qui portait sur les maisons numérique notre modèle de conception intégrait une classe mère Lieu, les lieux possédants des capteurs il était possible d’obtenir leurs informations à partir de la méthode getSensors(). La classe Partie héritant de Lieu et possédant elle-même un ensemble de lieux, la méthode getSensors() définie par sa classe mère n’est pas suffisante pour récupérer toutes les informations de tous les capteurs d’une partie. Il était donc nécessaire de redéfinir la méthode getSensors() dans la classe Partie grâce au polymorphisme.

Pure Fabrication

Dans certains problèmes il est possible qu’un « information expert » viole les règles de high cohesion et de low coupling. Le principe pure fabrication par l’utilisation de nouvelle classe « artificielle » traite ce problème.
Problème :
Comment faire quand les objets du domaine ne peuvent pas être utilisé en respectant la notion de faible couplage et de forte cohésion ?
Solution :
Affecter un ensemble fortement cohésif à une classe artificielle ou de commodité, qui ne représente pas un concept du domaine. Cela revient à créer une entité fabriquée de toutes pièces qui ne concorde pas avec le réel
Exemple
En reprenant l’exemple étudié en cours on remarque dans le premier diagramme que le joueur dépend fortement de la classe Dé il est impliqué dans une boucle et communique toujours avec la classe Dé ce qui correspond à un problème de couplage trop élevé. De plus le joueur possède trop de responsabilités il doit lancer le dé et s’occuper de la récupération de la valeur, ainsi ce trop grand nombre de responsabilités correspond à une faible cohésion. Pour résoudre ces problèmes on crée une classe artificielle Cornet, cette classe peu conforme avec le réel permet une répartition des responsabilités du joueur qui ne s’occupera plus que de lancer le cornet et un affaiblissement des dépendances de la classe Joueur.

Flèche de transition ou un truc qui montre la transformation