Le pattern Decorator en Python

Formation

En Ligne

Prix sur demande

Appeler le centre

Avez-vous besoin d'un coach de formation?

Il vous aidera à comparer différents cours et à trouver la solution la plus abordable.

Description

  • Typologie

    Formation

  • Méthodologie

    En ligne

Grâce à cette formation vous pourrez acquérir les connaissances nécessaires qui vous permettrons d’ajouter des compétences à votre profil et obtenir de solides aptitude qui vous offriront de nombreuses opportunités professionnelles.

Questions / Réponses

Ajoutez votre question

Nos conseillers et autres utilisateurs pourront vous répondre

À qui souhaitez-vous addresser votre question?

Saisissez vos coordonnées pour recevoir une réponse

Nous ne publierons que votre nom et votre question

Les Avis

Le programme

Introduction du cours

« La Programmation Orientée Objet, c'est bien joli, mais ça me fait passer deux fois plus de temps à réfléchir qu'à coder ! »

C'est fou le nombre de gens qui pensent cela… Et pourtant, s'ils savaient comme ils ont tort ! En effet, pour faire de la « belle » POO, il ne faut pas réfléchir deux fois plus que ce que l'on code… Ce devrait plutôt être cinq fois plus !

Cela peut sembler paradoxal, voire rébarbatif, mais c'est pourtant le reflet d'une réalité solide. La POO, ce n'est pas simplement la création d'une collection de classes liées entre elles par l'héritage ou l'encapsulation. Ces notions, dont la compréhension est extrêmement importante, ne sont que la « matière première » de la POO, un peu comme l'argile du potier. La véritable programmation objet, c'est l'art qui consiste à utiliser ces notions pour créer des programmes de qualité, facilement maintenables, dont les composants sont extensibles et réutilisables à souhait.

Ainsi, de la même manière que pour la pratique d'un art, pratiquer la POO demande d'acquérir un savoir-faire, ce qui nécessite de passer beaucoup de temps à réfléchir, analyser, s'entraîner, et accumuler de l'expérience.

Heureusement pour nous, l'expérience, ça peut se transmettre pour accélérer le processus. C'est d'ailleurs, comme nous allons le voir, ce qui a motivé la naissance des design patterns.

Dans ce tutoriel, nous allons étudier le design pattern Decorator, et son utilisation dans le langage Python. Cela va nous permettre de réfléchir sur plusieurs pratiques, bonnes et mauvaises, et de découvrir des pistes de réflexion que vous pourrez suivre afin de progresser dans votre pratique de la POO.

Pour suivre ce tutoriel, vous aurez besoin :

  • de connaître le langage Python,

  • d'avoir appris la POO en Python, et, de préférence, de l'avoir pratiquée,

  • d'avoir le goût du travail bien fait. :p

Les codes d'exemple de ce tutoriel ont été réalisés avec Python 3.

IntroductionQu'est-ce qu'un programme de qualité ?

Je suis sûr que si j'effectuais un sondage ouvert auprès de plein de personnes différentes (développeurs, utilisateurs, éditeurs…), j'obtiendrais des tonnes de réponses uniques à cette question. Néanmoins, l'expérience prouve qu'il est possible de tracer, dans les grandes lignes, plusieurs caractéristiques générales qui différencient un programme quelconque d'un bon programme, et je vais me permettre de les résumer grossièrement. Un programme de qualité, c'est avant tout un programme :

1. qui fait exactement ce que l'utilisateur attend de lui ;
2. dont le code est facile à comprendre et à maintenir ;
3. dont le code est facile à faire évoluer et à réutiliser.

Dans ce tutoriel, étant donné que nous allons parler de programmation et de conception orientée objet, nous allons surtout nous pencher sur les deux derniers aspects.

Pourquoi est-ce si difficile de concevoir un programme de qualité ?

S'il devait n'exister qu'une seule vérité constante sur le développement d'applications, avec laquelle tout programmeur est amené un jour ou l'autre à se battre, ce serait certainement le changement. En effet, quel que soit le temps que vous passerez à réfléchir avec application sur le design d'un programme, celui-ci sera toujours, un jour ou l'autre, amené à être modifié, pour satisfaire les nouveaux besoins d'un client, pour ajouter la fonctionnalité à laquelle vous venez de penser vous-même, ou, plus généralement, pour que votre projet puisse continuer à vivre.

C'est le fait de savoir gérer, voire anticiper ce changement, qui est difficile. Heureusement, des générations de développeurs et de concepteurs avant nous se sont déjà penchés sur la question, et nous disposons aujourd'hui, en tant que développeurs, de méthodes et d'outils pour nous y aider. Parmi eux se trouvent les grands principes de la POO, et les design patterns.

Les design patterns, c'est quoi ?

Lorsque l'on doit concevoir une application permettant de répondre à une problématique donnée, il n'est pas rare que l'on puisse reconnaître des structures semblables à ce que l'on a déjà fait par le passé.

D'ailleurs, cela a certainement déjà dû vous arriver. Ne vous êtes-vous jamais surpris à penser quelque chose comme : « tiens, si j'organise mes objets de cette manière, je vais avoir le même soucis que quand j'ai développé tel projet le mois dernier », et adapter votre architecture en sachant que de cette façon, vous évitez de reproduire un problème que vous avez déjà résolu dans un autre contexte ?

Ces structures redondantes, vous vous doutez bien que vous n'êtes pas le premier à les découvrir… De nombreux développeurs avant nous les ont déjà rencontrées. Certains d'entre eux les ont même étudiées et, mieux encore, ils les ont partagées afin de permettre aux autres développeurs de gagner du temps le jour où ils rencontreront eux-mêmes un problème de conception similaire. On appelle ces structures des design patterns (en français, des patrons de conception).

Historiquement, l'étude des « design patterns » est née dans les années 1990, et a été popularisée en 1994, avec le livre remarquable du « Gang of Four » (le « gang des quatre ») intitulé Design Patterns: Elements of Reusable Object-Oriented Software. Cet ouvrage recense de nombreux patterns reconnus et éprouvés par les développeurs, et en explique le fonctionnement, les intérêts, les domaines d'applications, et les limites : en un mot comme en cent, c'est la bible des patrons de conception.

Pour résumer l'idée, un patron de conception :

  • est une solution générique pour un problème de conception particulier ;

  • porte un nom, ce qui permet aux développeurs qui sont à l'aise avec les design patterns de communiquer leurs idées de manière plus efficace ;

  • est un outil servant à rendre un programme plus facile à maintenir et à faire évoluer ;

  • est le fruit de l'expérience de programmeurs qui ont été amenés à régler un même problème dans des contextes différents, et non une solution théorique.

Dans ce tutoriel, nous allons étudier un patron de conception particulier, le « Decorator » (en français, Décorateur). J'utiliserai de préférence son nom anglophone, car, comme je viens de le dire, le nom d'un patron de conception permet aux développeurs de savoir qu'ils parlent bien de la même chose : les communautés de développeurs s'exprimant le plus souvent en anglais, il est préférable de retenir les patterns sous leur nom originel, plutôt que leur traduction.

Le pattern Decorator

Le Decorator est l'un des patrons de conception les plus simples à comprendre et à mettre en œuvre, mais aussi l'un des plus formateurs.

Non content de résoudre un problème de conception fréquent (que nous allons voir dans un instant), il a aussi le mérite d'attirer l'attention des débutants sur le piège qui consiste à penser que l'héritage est la « réponse par défaut » à tous les problèmes en POO. Qui plus est, pour nous, pythonistes, il a une résonance particulière, étant donné que Python propose une syntaxe pour utiliser des décorateurs statiques de manière élégante. Bien que différent du patron de conception du même nom, ce système repose sur un principe assez proche.

Les buts de ce tutoriel sont donc multiples :

  • découvrir un design pattern (peut-être votre premier…), qui vous sera probablement utile à l'avenir, et vous montrer la puissance de ce genre de solution ;

  • initier une réflexion un peu plus approfondie sur les rôles de l'héritage et de l'encapsulation en POO ;

  • (re-)découvrir ensemble plusieurs grands principes de la POO ;

  • avoir une vision plus globale du principe de décoration, qui est implémenté dans votre langage de programmation préféré.

Dans la prochaine partie, nous allons définir un cas « plus ou moins concret », où le Décorateur prend toute sa valeur, et qui nous servira d'exemple tout le long de ce tutoriel.

Notre cas d'étude : le MacD'halalMise en situation

Vous êtes chargé de développer une application pour le compte du gérant d'un petit restaurant qui vend des kebabs et autres sandwiches dits "de spécialité turque". Celui-ci souhaite faire décoller son business en créant une franchise, sous laquelle il pourra ouvrir plusieurs autres restaurants identiques, placés à des lieux stratégiques dans Paris, voire, à terme, dans toute la France.

L'image de marque que le gérant veut donner à sa clientèle est celle d'un établissement « à la carte », où tous les sandwiches vendus sont personnalisables (avec leurs prix modifiés en conséquence) : par exemple, si un client commande un kebab "sans oignon", il bénéficiera d'une légère réduction sur le prix de son sandwich, pour lui donner le sentiment qu'il ne paye « que ce qu'il mange ». Il en va de même pour les suppléments que le client décide d'ajouter à son sandwich : le supplément se répercute par une légère augmentation du prix.

Par ailleurs, il n'est pas impossible qu'un site internet soit créé, de manière à mettre en place, dans les prochaines années, un service de livraison à domicile, ou que des bornes de commande rapide par carte bleue soient installées dans les restaurants afin de gérer de manière plus fluide l'affluence de clients pendant les heures de pointe.

Votre mission, si vous l'acceptez, est de créer un logiciel de gestion des commandes pour ce restaurateur. Le programme sera chargé de gérer la prise de commandes et communiquer avec une interface pour que les vendeurs puissent, en quelques touches sur un écran tactile, sélectionner un sandwich et le personnaliser selon la demande du client, afin que le prix soit calculé automatiquement.

Évidemment, le cœur de ce programme aura aussi des chances d'être repris à l'avenir par un service web pour prendre les commandes de livraison à domicile ou par l'interface des bornes de commande rapide : il faut donc que son architecture soit suffisamment souple pour qu'elle puisse être adaptée simplement le jour où cela deviendra nécessaire.

Portée de notre étude

Bien évidemment, nous n'allons pas créer un service web ou une interface pour écran tactile dans ce tutoriel : tout ce qui nous intéresse aujourd'hui, c'est le cœur du programme, la logique qui tourne derrière l'interface. Plus précisément, l'aspect qui nous intéresse dans ce tutoriel, c'est comment nous allons modéliser nos kebabs afin que l'on puisse les personnaliser facilement pour le client.

Cette personnalisation, ici, se traduit par l'ajout ou le retrait de certains ingrédients dans le sandwich. Pour l'instant, nous allons nous concentrer sur un seul type de sandwich, le kebab. On pourra donc, par exemple, avoir des kebabs :

  • sans oignon,

  • sans salade,

  • sans tomate,

  • avec de la viande de poulet au lieu du mouton,

  • avec supplément fromage,

  • avec supplément oignon,

  • avec supplément salade,

  • avec supplément tomate,

  • avec supplément viande,

  • ...

ainsi que toutes les combinaisons imaginables entre ces diverses possibilités. Le but recherché, c'est une manière de créer simplement ces sandwiches, et d'afficher dans la console leur prix ainsi que leur composition (comme sur un ticket de caisse, en fait).

Comme nous allons le voir dans la prochaine partie, tout se joue à la conception.

Avant d'aller plus loin…

Faites-moi plaisir : prenez le temps de réfléchir à la façon dont vous vous y prendriez, sans plus d'information que ce que je viens de vous donner, pour modéliser des kebabs personnalisables. Si vous réfléchissez de manière autonome avant de lire la suite, vous découvrirez seul les problèmes qui se posent à la conception (ou au moins une partie d'entre eux), et vous retiendrez à coup sûr plus d'informations utiles de ce tutoriel. ;)

Premiers jets

Dans cette partie, nous allons chercher ensemble le meilleur moyen de modéliser ce problème.
Pour ce faire, nous allons procéder par itérations, c'est-à-dire que l'on va commencer par une modélisation naïve que nous allons corriger chaque fois que l'on constatera un problème.

Un kebab simple

Commençons déjà par créer notre classe Kebab. Un kebab simple est composé de salade, de tomates, d'oignons, de viande de mouton et de sauce, et il est accompagné de frites. Il a un prix et peut afficher sa composition. Voici une première implémentation possible :

PRIX_BASE = 3.8 PRIX_SALADE = 0.2 PRIX_TOMATES = 0.2 PRIX_OIGNONS = 0.3 PRIX_FRITES = 0.5 class Kebab: def __init__(self, sauce): self.sauce = sauce self.base = PRIX_BASE self.salade = PRIX_SALADE self.tomates = PRIX_TOMATES self.oignons = PRIX_OIGNONS self.frites = PRIX_FRITES @property def prix(self): return (self.base + self.salade + self.tomates + self.oignons + self.frites) def __str__(self): return 'Kebab' def __repr__(self): s = 'Kebab ({0}) ;'.format(self.prix) for it in self.__dict__.items(): s +=' {0} ({1}) '.format(*it) return s

Notre classe Kebab ne contient que quatre méthodes.
Dans le constructeur (__init__), on initialise les prix des ingrédients. Ceci se fait à partir de valeurs déclarées dans des constantes globales. Dans le cas réel, il y aurait peut-être besoin de récupérer ces valeurs sur une base de données, mais cela dépasse la portée de ce tutoriel.

La méthode prix définit une propriété du même nom : si vous n'êtes pas à l'aise avec cette notation, vous pourrez en apprendre plus sur cette page de la documentation de Python. Clairement, elle calcule le prix du kebab en fonction de celui de ses ingrédients.

Enfin les méthodes __repr__ et __str__ permettent d'afficher l'objet sous forme de chaîne de caractères. C'est grâce à ces méthodes que nous allons contrôler le bon fonctionnement de notre programme.

Voici un exemple d'utilisation :

>>> a = Kebab('ketchup') >>> print(a) Kebab >>> a Kebab (5.0) : salade (0.2) oignons (0.3) frites (0.5) tomates (0.2) base (3.8) sauce (ketchup) Utilisons l'héritage !

Une première idée que l'on peut explorer, pour modéliser la personnalisation de nos sandwiches, est d'utiliser simplement l'héritage. En effet, on peut partir du constat qu'un « kebab sans oignon » EST UN kebab. La relation EST UN étant traduite le plus souvent en POO par l'héritage, il suffit de dire que la classe KebabSansOignon dérive de la classe Kebab.

Bien ! Partons sur cette idée.

class KebabSansOignon(Kebab): def __init__(self, sauce): super().__init__(sauce) self.oignons = 0 # Pas d'oignon def __str__(self): return 'Kebab sans oignon'...

Appeler le centre

Avez-vous besoin d'un coach de formation?

Il vous aidera à comparer différents cours et à trouver la solution la plus abordable.

Le pattern Decorator en Python

Prix sur demande