Temps estimé: 30 minutes
Série sur l'abstraction
Si vous avez du mal à comprendre et répondre aux concepts des questions, vous pouvez vous référer au livre Practical Object-Oriented Design et lire les chapitres 4 à 6.
Question 1
Donnez un exemple de la vie quotidienne qui fait appel au principe d’abstraction.
Tout élément qui cache certains détails d’implémentation/façon de fonctionner afin de n’exposer qu’un concept général plus simple à utiliser et à comprendre.
Ex. une laveuse, un guichet automatique, un volant d’une voiture, etc.
Question 2
Étant donné les 2 situations suivantes:
Situation A:
- Je crée une classe X puis une classe Y.
- Je constate une duplication de code entre X et Y.
- J’en extrais immédiatement une abstraction pour éviter la duplication.
Situation B:
Je crée une classe X puis une classe Y.
Je constate une duplication de code entre X et Y.
Je laisse la duplication.
2.1 Donnez un cas pour lequel A pourrait être préférable à B.
2.2 Donnez un cas pour lequel B pourrait être préférable à A.
2.1 Si nous avons assez d’informations concernant X, Y et leur contexte qui permettent de déterminer que X et Y offrent vraiment la même capacité et que le client a besoin de cette capacité, alors il pourrait être préférable d’immédiatement créer l’abstraction.
2.2 S’il manque des informations concernant X et Y qui permettent de déterminer avec confiance que X et Y ont les mêmes capacités, alors il est préférable d’attendre d’avoir davantage d’informations avant d’extraire une abstraction, car il est fort possible que des changements surviennent et invalident l'abstraction. Ou si on sait pertinemment que X et Y ont deux contextes différents. Ceci dit, la composition est souvent utilisée pour ne pas avoir de duplication, sans toutefois créer tout de suite une abstraction.
Post intéressant à lire concernant les mauvaises abstractions: The Wrong Abstraction
Question 3
Expliquez dans vos mots ce que signifie "Composition over Inheritance".
Il est préférable de privilégier la composition par rapport à l'héritage/abstraction, car les conséquences d'un mauvais héritage/abstraction sont coûteuses. Passer par une étape intermédiaire, c'est-à-dire la composition, permet de ne pas avoir de duplication, en attendant d'avoir davantage d'informations sur le contexte et la capacité des éléments afin d'en extraire une abstraction ou une hiérachie polymorphique.
Question 4
La semaine passée vous avez vu un exemple d’une leaky abstraction (voir exercice semaine 2 OO et abstraction question 9), cette fois, expliquez dans vos propres mots ce qu’est une leaky abstraction et qu’est-ce que la loi des leaky abstractions.
Caractéristique d’une abstraction qui dévoile des détails qu’elle est supposée abstraire. La loi des leaky abstractions stipule qu’aucune abstraction ne peut parfaitement nous protéger des problèmes. Elle stipule également que pour utiliser l’abstraction “leaky”, il faut que les développeurs connaissent les détails d’implémentation qui se cachent en dessous afin de bien utiliser l’abstraction et comprendre les impacts de son utilisation.
Question 5
Quelles sont les conséquences d’une abstraction trop générale?
Une abstraction qui s’applique à tous les contextes au final ne s’applique à aucun contexte. Si une abstraction est trop générale, il devient difficile de comprendre dans quel cas l’utiliser et ce qu’elle fait réellement.
Ex. une interface avec une méthode handle
ou une interface qui s'appelle Stuff
.
Question 6
Quelles sont les conséquences d’une abstraction trop spécifique?
L’abstraction sera peu utile puisqu’il faudra effectuer des changements à toutes les fois que les spécificités changeront (vouloir mettre un contrat en fonction du degré d'intimité ce qui entraîne la propagation des changements) alors qu’un des objectifs de poser une abstraction est de se protéger des changements. De plus elle ne pourra probablement pas s'appliquer à plusieurs contextes puisque trop précise.
Question 7
Dans quel cas il serait acceptable d'avoir une abstraction spécifique?
Une interface peut être spécifique (avoir une capacité spécifique) si elle n'a pas le même cycle de vie que son appelant, c'est-à-dire que l'interface ne change pas à chaque fois que l'implémentation change. De plus, il ne faut pas qu'il y ait des détails d'implémentation (fuite d'abstraction).
Question 8
Dans quel cas serait-il préférable d’utiliser une interface et dans quel cas est-il préférable d’utiliser une classe abstraite (en considérant bien sûr que le langage permet les classes abstraites).
Il serait préférable d’utiliser une classe abstraite lorsque les enfants ont des comportements communs qu’il est possible d’extraire et que cette partie sera instrinsèquement commune aux futures implémentations. Alors qu’une interface est préférable si tous les enfants ont des implémentations différentes.
Question 9
Expliquez la différence entre l’abstraction et l’indirection (composition).
L’abstraction est le fait de cacher certains détails d’implémentation afin d’en simplifier l’utilisation et de se protéger des changements.
L’indirection est le fait d’appeler un élément par un autre élément c’est à dire d’ajouter une couche intermédiaire afin de:
- ajouter une transformation sur un objet
- simplifier la communication entre les deux objets
- ajouter des éléments de sécurité
- etc.
L’abstraction fait appel à l’indirection, mais l’indirection ne fait pas nécessairement référence à l’abstraction.
Question 10
Concevez un système (un simple diagramme suffit) qui permet de répondre à ce besoin.
Une voiture doit afficher sa vitesse sur 3 types d'affichage possibles en fonction du modèle de la voiture: digital, à aiguille ou en texte.
┌─────┐ displaySpeed() ┌─────────────┐
│ Car │ ────────────────────> │ Speedometer │
└─────┘ │ < I > │
└─────────────┘
△
│
┌──────────────────────────┼─────────────────────────┐
│ │ │
┌─────────┴──────────┐ ┌─────────┴─────────┐ ┌─────────┴──────────┐
│ DigitalSpeedometer │ │ AnalogSpeedometer │ │ ConsoleSpeedometer │
└────────────────────┘ └───────────────────┘ └────────────────────┘