1 00:00:00,580 --> 00:00:02,870 Bonjour. Dans cette séquence, nous faisons suite à la 2 00:00:03,070 --> 00:00:05,450 séquence précédente dans laquelle je disais que les 3 00:00:05,650 --> 00:00:07,010 petites méthodes, c'était vraiment bien. 4 00:00:07,530 --> 00:00:09,000 Ici, je vais vous montrer des exemples. 5 00:00:09,770 --> 00:00:13,480 Pour revenir rapidement sur la séquence précédente, un 6 00:00:13,680 --> 00:00:17,540 envoi de messages c'est un choix masqué parce qu'il peut 7 00:00:17,740 --> 00:00:21,560 y avoir plusieurs implémentations possibles qui vont être appelées. 8 00:00:22,150 --> 00:00:25,460 Pharo choisit laquelle en fonction du receveur du message. 9 00:00:26,570 --> 00:00:28,280 C'est la hiérarchie de classes qui définit les choix: 10 00:00:28,480 --> 00:00:29,830 plus on a de classes, plus on a de choix. 11 00:00:31,030 --> 00:00:33,050 Et on peut ajouter de nouveaux choix facilement en créant 12 00:00:33,250 --> 00:00:34,010 de nouvelles sous-classes. 13 00:00:35,870 --> 00:00:40,130 Les sous-classes peuvent redéfinir et raffiner le code de leur super classe. 14 00:00:42,120 --> 00:00:45,700 En fait, envoyer un message, c'est laisser la possibilité 15 00:00:46,360 --> 00:00:49,230 à des sous-classes de changer le comportement. 16 00:00:50,720 --> 00:00:53,680 On va s'intéresser au design pattern Template Method, que 17 00:00:53,880 --> 00:00:56,500 vous trouverez dans le livre de "Design pattern". 18 00:00:57,730 --> 00:01:00,140 Une template Method c'est quoi ? 19 00:01:00,340 --> 00:01:03,040 C'est un squelette, ça définit globalement le 20 00:01:03,240 --> 00:01:08,160 comportement d'un algorithme, par exemple avec des trous 21 00:01:08,360 --> 00:01:12,080 à l'intérieur et ces trous vont pouvoir être redéfinis par les sous-classes. 22 00:01:13,940 --> 00:01:17,840 Là, j'ai un exemple d'algorithme qui fait quelque chose 23 00:01:18,040 --> 00:01:21,830 mais on ne sait pas trop quoi, qui ensuite va faire 24 00:01:22,030 --> 00:01:24,470 quelque chose qui va être dans une méthode hookMethod1, 25 00:01:25,810 --> 00:01:29,030 puis autre chose, puis quelque chose qui se trouve dans hookMethod2. 26 00:01:29,230 --> 00:01:34,130 hookMethod1 et 2 puisque ce sont des méthodes à 27 00:01:34,330 --> 00:01:36,410 part entière, elles vont pouvoir être redéfinies dans les sous-classes. 28 00:01:37,890 --> 00:01:40,730 Il y a 2 possibilités pour hookMethod1 et 2. 29 00:01:41,850 --> 00:01:46,480 Ces méthodes peuvent avoir 30 00:01:46,820 --> 00:01:49,530 une implémentation par défaut ou pas. 31 00:01:50,290 --> 00:01:53,590 Ici, on peut dire que hook1 a une implémentation par 32 00:01:53,790 --> 00:01:56,430 défaut, c'est-à-dire que si la sous-classe ne propose 33 00:01:56,630 --> 00:02:00,480 rien hook1 a une implémentation par défaut qui 34 00:02:02,410 --> 00:02:07,290 va marcher. Ou alors, on peut dire que 35 00:02:07,490 --> 00:02:10,060 hookMethod2 n'a pas d'implémentation et qu'il faut 36 00:02:10,260 --> 00:02:12,230 absolument que la sous-classe définisse un comportement. 37 00:02:12,430 --> 00:02:15,470 Là, vous avez le choix en tant que concepteur de la 38 00:02:15,670 --> 00:02:18,310 classe, soit de fournir une implémentation, un 39 00:02:18,510 --> 00:02:19,610 comportement par défaut, soit non. 40 00:02:20,710 --> 00:02:23,090 On va prendre un premier exemple, l'exemple de printString. 41 00:02:24,430 --> 00:02:27,010 L'idée, c'est que si j'envoie le message printString à un 42 00:02:27,210 --> 00:02:30,560 objet, j'obtiens une chaîne de caractères qui représente cet objet. 43 00:02:31,370 --> 00:02:35,640 Là, j'ai un délai. Je crée un délai 44 00:02:36,650 --> 00:02:40,590 de 10 secondes. Si j'envoie le message printString à ce 45 00:02:40,790 --> 00:02:45,460 delay là, je vois'a delay'et entre parenthèses, la 46 00:02:45,660 --> 00:02:47,260 valeur en millisecondes du delay. 47 00:02:48,470 --> 00:02:51,500 La méthode printString est implémentée dans la classe 48 00:02:51,700 --> 00:02:54,860 objects de cette façon-là. En fait, elle envoie le 49 00:02:55,060 --> 00:02:57,560 message printString LimitedTo. Cette implémentation-là 50 00:02:57,760 --> 00:03:02,450 récupère une chaîne de caractères qui représente 51 00:03:03,230 --> 00:03:07,710 l'objet, et ensuite si cette chaîne de 52 00:03:07,910 --> 00:03:12,110 caractères-là est trop grande on peut la couper à une 53 00:03:12,310 --> 00:03:16,780 certaine valeur, la limite, et concaténer à la fin point 54 00:03:17,000 --> 00:03:19,520 point point etc. pour dire que la chaîne de caractères n'est pas terminée. 55 00:03:20,950 --> 00:03:23,070 Là, l'important ici c'est de voir que 56 00:03:23,270 --> 00:03:27,920 printStringLimitedTo envoie le message printOn à self. 57 00:03:28,500 --> 00:03:33,060 C'est cette méthode-là qui va être redéfinie dans les sous-classes ou pas. 58 00:03:34,300 --> 00:03:39,000 Si je regarde ce que retourne printString pour un 59 00:03:39,200 --> 00:03:43,660 nœud et pour une pomme, là Node new retourne a Node. 60 00:03:44,340 --> 00:03:48,330 Ça, c'est le printString de la classe Node. 61 00:03:49,220 --> 00:03:53,190 Et là an Apple, c'est le prinString de la classe Apple. 62 00:03:53,940 --> 00:03:56,530 On voit que ce comportement est le comportement par 63 00:03:56,730 --> 00:03:59,180 défaut et il est implémenté dans la classe objects. 64 00:04:00,370 --> 00:04:03,300 Le comportement par défaut du printString pour n'importe 65 00:04:03,500 --> 00:04:05,540 quel objet, c'est 1, 66 00:04:08,610 --> 00:04:12,400 récupérer le nombre de la classe, donc là Node et Apple, 67 00:04:13,180 --> 00:04:16,330 et ensuite si ce nom de classe commence par une voyelle 68 00:04:17,740 --> 00:04:21,430 alors on va préfixer par an, et si ça commence par une 69 00:04:21,630 --> 00:04:22,860 consonne on va préfixer par a. 70 00:04:23,170 --> 00:04:25,060 C'est ça qui nous permet d'avoir "a node" et "an apple. 71 00:04:25,260 --> 00:04:29,910 " C'est l'implémentation par 72 00:04:30,110 --> 00:04:33,840 défaut et il est possible de changer ce comportement par 73 00:04:34,040 --> 00:04:35,930 défaut en ré implémentant printOn. 74 00:04:37,240 --> 00:04:41,360 Donc là pour un delay on voit que le print string d'un 75 00:04:41,560 --> 00:04:45,820 delay, ça commence par ce que retourne print on par 76 00:04:46,020 --> 00:04:49,490 défaut, c'est-à-dire a délai, mais qu'ensuite on ajoute 77 00:04:50,230 --> 00:04:52,220 entre parenthèses le delay en millisecondes. 78 00:04:52,950 --> 00:04:55,710 C'est exactement ce que fait l'implémentation de la méthode printOn. 79 00:04:57,000 --> 00:04:59,680 Elle commence par demander à la super classe le 80 00:04:59,880 --> 00:05:04,310 printString par défaut, et ensuite ça ajoute la 81 00:05:04,510 --> 00:05:07,230 parenthèse à un nombre de millisecondes préfixé 82 00:05:09,480 --> 00:05:10,520 ainsi que la parenthèse fermante. 83 00:05:11,890 --> 00:05:14,750 Là nous avons vu du raffinement. 84 00:05:15,160 --> 00:05:19,660 La classe delay raffine l'implémentation de la méthode 85 00:05:19,860 --> 00:05:21,360 print on de la classe objects. 86 00:05:21,700 --> 00:05:24,810 Et une classe peut aussi redéfinir complètement le comportement. 87 00:05:26,010 --> 00:05:30,010 C'est le cas pour les booléens par exemple. 88 00:05:30,210 --> 00:05:35,140 Si j'affiche false, ça me retourne false et 89 00:05:35,340 --> 00:05:39,040 donc on n'a pas a false, on a juste false. 90 00:05:39,640 --> 00:05:43,090 Pour ça, on envoie juste la chaîne de caractères false 91 00:05:43,670 --> 00:05:45,300 dans le stream passé en paramètre à printOn. 92 00:05:46,510 --> 00:05:47,600 C'est une redéfinition complète. 93 00:05:47,800 --> 00:05:51,290 Un autre exemple de redéfinition complète, c'est pour les intervalles. 94 00:05:52,210 --> 00:05:54,510 Un intervalle définit un ensemble de valeurs entre une 95 00:05:54,710 --> 00:05:56,430 valeur minimum et une valeur maximum. 96 00:05:58,200 --> 00:06:02,010 L'intervalle 1 à 100 s'affiche parenthèse 1 to: 100 parenthèse. 97 00:06:04,450 --> 00:06:09,290 L'intervalle 1 à 100 par "pas de 3", donc 1, 98 00:06:09,490 --> 00:06:14,410 4, et caetera, affiche la même chose mais avec le pas en 99 00:06:15,780 --> 00:06:18,740 plus. Comment est-ce que c'est implémenté? 100 00:06:19,110 --> 00:06:23,550 La classe Interval redéfinit la méthode Print on et 101 00:06:23,750 --> 00:06:26,000 envoie différents messages au aStream passé en paramètre. 102 00:06:26,760 --> 00:06:30,270 Déjà on affiche une parenthèse, c'est la parenthèse qui s'affiche 103 00:06:30,470 --> 00:06:34,480 ici et ici, puis on affiche la valeur initiale enfin le 104 00:06:34,680 --> 00:06:39,180 début de l'intervalle, c'est-à-dire 1 et 1 qui se trouve ici. 105 00:06:39,760 --> 00:06:41,110 Puis on affiche 2. 106 00:06:44,710 --> 00:06:46,180 Puis on affiche la valeur finale. 107 00:06:46,380 --> 00:06:50,880 C'est 100 et 100. Enfin, s'il y a un 108 00:06:51,080 --> 00:06:55,140 pas différent de 1 qui est le défaut, on affiche 109 00:06:56,150 --> 00:06:59,550 le pas et 110 00:07:01,200 --> 00:07:05,340 à la fin on met la parenthèse. 111 00:07:06,050 --> 00:07:09,080 Donc on a vu que printString utilisait le design pattern 112 00:07:09,280 --> 00:07:12,550 template method pour que les classes puissent implémenter 113 00:07:12,750 --> 00:07:14,800 leurs propres représentations textuelles. 114 00:07:15,000 --> 00:07:19,160 On va avoir un autre exemple sous la forme du message 115 00:07:19,360 --> 00:07:24,300 copie, qui permet de prendre un objet et 116 00:07:24,500 --> 00:07:25,810 d'en créer un clone. 117 00:07:27,720 --> 00:07:31,630 La copie d'objets c'est complexe et il peut y avoir 118 00:07:31,850 --> 00:07:35,630 différentes stratégies, donc chaque classe peut décider à 119 00:07:35,830 --> 00:07:39,110 quoi doit ressembler une copie d'une de ses instances. 120 00:07:40,210 --> 00:07:42,720 Il existe une solution simple sous la forme d'un template 121 00:07:42,920 --> 00:07:46,450 method qui met en jeu les méthodes copy et postCopy. 122 00:07:47,000 --> 00:07:48,710 Copy, c'est le template method. 123 00:07:48,910 --> 00:07:50,560 Postcopy, c'est le hook. 124 00:07:52,020 --> 00:07:55,080 Dans la classe objects, il y a une méthode copy, je vous 125 00:07:55,280 --> 00:07:59,300 laisse lire le commentaire, et cette méthode-là 126 00:08:01,300 --> 00:08:05,950 envoie shallowCopy comme message à self, puis 127 00:08:06,740 --> 00:08:08,550 postCopy sur le résultat. 128 00:08:09,160 --> 00:08:14,080 ShallowCopy, ça crée un nouvel objet qui 129 00:08:14,280 --> 00:08:17,820 partage toutes les variables d'instances avec l'objet de base. 130 00:08:18,610 --> 00:08:22,090 On a 2 objets et toutes leurs variables d'instances sont les mêmes. 131 00:08:22,300 --> 00:08:24,280 Donc si je modifie la variable d'instance d'un des 132 00:08:24,480 --> 00:08:26,010 objets, je modifie la variable d'instance de l'autre objet. 133 00:08:27,670 --> 00:08:31,940 Ça, c'est le comportement par défaut 134 00:08:34,680 --> 00:08:35,440 de shallowCopy. 135 00:08:35,950 --> 00:08:40,140 Maintenant suivant ce que va faire postCopy, ce partage 136 00:08:40,340 --> 00:08:41,610 va se faire ou ne va pas se faire. 137 00:08:41,810 --> 00:08:44,230 Si postCopy est vide, toutes les variables sont partagées 138 00:08:44,480 --> 00:08:47,470 et les classes peuvent décider de mettre différentes 139 00:08:47,670 --> 00:08:50,070 choses dans postCopy, pour partager certaines variables 140 00:08:50,270 --> 00:08:51,880 et pas d'autres ou ne partager aucune variable. 141 00:08:53,080 --> 00:08:57,480 Par défaut postCopy partage tout, donc ça retourne juste 142 00:08:58,130 --> 00:09:02,750 l'objet en cours. Mais on peut tout à fait imaginer d'autres 143 00:09:02,950 --> 00:09:04,000 implémentations de postCopy. 144 00:09:04,180 --> 00:09:08,710 Là, par exemple dans la classe Bag, Bag c'est un type de 145 00:09:08,910 --> 00:09:13,110 collection, et sa méthode de post Copy copie son contenu. 146 00:09:14,750 --> 00:09:18,160 Un Bag a une variable d'instances contents et les 147 00:09:18,750 --> 00:09:21,720 concepteurs de la classe Bag ont décidé que lorsqu'on 148 00:09:21,920 --> 00:09:25,520 fait une copie d'un Bag, on ne veut pas partager la 149 00:09:25,720 --> 00:09:27,690 variable contents, on veut 2 variables contents séparées. 150 00:09:28,330 --> 00:09:29,840 Au début, elles auront la même valeur mais si j'en 151 00:09:30,040 --> 00:09:31,490 modifie une, je ne modifierais pas l'autre. 152 00:09:33,740 --> 00:09:37,170 Là, l'idée c'est que postCopy c'est un message qui est 153 00:09:37,370 --> 00:09:40,610 envoyé à la copie, donc au nouvel objet, qui partage 154 00:09:43,370 --> 00:09:45,810 toutes les variables d'instances, et si on ne veut pas 155 00:09:46,010 --> 00:09:48,410 les partager il suffit d'en créer de nouvelles et de 156 00:09:48,610 --> 00:09:49,730 décider quelle valeur on met dedans. 157 00:09:50,820 --> 00:09:54,000 Là, dans ma variable contents, je vais mettre une copie 158 00:09:54,200 --> 00:09:56,380 du contents d'origine. Comme ça je ne partage plus le 159 00:09:56,580 --> 00:09:59,250 contents, chaque copie de mon Bag a son propre contents. 160 00:10:00,700 --> 00:10:03,220 Pour le dictionnaire, on veut aller encore plus loin. 161 00:10:03,720 --> 00:10:06,010 Un dictionnaire en fait c'est une collection de paires 162 00:10:06,210 --> 00:10:08,570 clefs valeurs, donc une collection d'associations. 163 00:10:09,260 --> 00:10:13,680 Et si on copie un 164 00:10:13,880 --> 00:10:16,050 dictionnaire, on veut copier la collection. 165 00:10:16,250 --> 00:10:18,840 Donc chaque dictionnaire va avoir sa propre collection de paires. 166 00:10:19,060 --> 00:10:21,070 Mais on veut aussi que chaque paire soit différente de 167 00:10:21,270 --> 00:10:23,860 façon à ce que si je modifie une paire d'un côté, ça ne 168 00:10:24,060 --> 00:10:26,280 va pas modifier une paire de l'autre côté. 169 00:10:27,200 --> 00:10:31,270 Pour ça, je copie le tableau mais je copie aussi chaque 170 00:10:31,470 --> 00:10:34,510 paire à l'intérieur et c'est exactement ce qui se passe là. 171 00:10:35,220 --> 00:10:37,130 En conclusion, le design pattern template method est 172 00:10:37,330 --> 00:10:40,530 vraiment très très fréquent. En fait, c'est un signe de 173 00:10:40,730 --> 00:10:43,080 bonne conception et si vous faites de la bonne conception 174 00:10:43,280 --> 00:10:45,250 objet, vous allez vous retrouver avec des templates 175 00:10:45,450 --> 00:10:48,140 methods partout, c'est parfaitement normal et c'est même une bonne chose. 176 00:10:49,340 --> 00:10:53,730 N'hésitez pas à vous en servir, ça permet aux 177 00:10:53,930 --> 00:10:57,350 sous-classes de définir du comportement et de modifier en 178 00:10:57,550 --> 00:10:59,380 partie le comportement de la super classe.