1 00:00:00,480 --> 00:00:03,920 Today we will carry on with the previous session 2 00:00:04,080 --> 00:00:07,280 where I explained that small methods were good. 3 00:00:07,440 --> 00:00:09,160 Today I'll show some examples. 4 00:00:09,320 --> 00:00:12,840 But first, let's quickly review our previous session. 5 00:00:13,000 --> 00:00:15,280 Sending a message leads to a choice. 6 00:00:15,440 --> 00:00:19,640 A masked choice because several possible implementations 7 00:00:19,800 --> 00:00:21,560 will be called up. 8 00:00:22,040 --> 00:00:25,960 And Pharo makes a choice depending on the message receiver. 9 00:00:26,480 --> 00:00:30,360 Class hierarchy defines choices: More classes = more choices. 10 00:00:30,600 --> 00:00:34,360 And you can easily add new choices by creating subclasses. 11 00:00:35,760 --> 00:00:40,480 Subclasses can redefine or refine the code of their superclass. 12 00:00:42,000 --> 00:00:43,920 And sending a message 13 00:00:44,080 --> 00:00:49,360 means giving subclasses the possibility to change behavior. 14 00:00:50,520 --> 00:00:54,080 Today we'll look at the Design Pattern template method. 15 00:00:54,240 --> 00:00:56,880 You'll find it in the Design Pattern manual. 16 00:00:57,640 --> 00:00:59,960 What is a template method? 17 00:01:00,120 --> 00:01:04,600 It's a skeleton that defines the overall behavior 18 00:01:04,760 --> 00:01:08,800 of an algorithm, for example, with hooks inside. 19 00:01:08,960 --> 00:01:12,680 And these hooks can be redefined by subclasses. 20 00:01:13,840 --> 00:01:16,000 This is an algorithm. 21 00:01:16,320 --> 00:01:19,320 It does something, we don't exactly know what. 22 00:01:20,280 --> 00:01:25,320 Next, it does something in hookMethod 1, 23 00:01:25,720 --> 00:01:27,080 then something else, 24 00:01:27,240 --> 00:01:29,480 and then something in hookMethod2. 25 00:01:29,640 --> 00:01:34,200 Since hookMethods 1 and 2 are both complete methods, 26 00:01:34,360 --> 00:01:37,040 they can be redefined in the subclasses. 27 00:01:37,600 --> 00:01:41,320 There are 2 possibilities, one each for hookMethod 1 and 2. 28 00:01:42,760 --> 00:01:46,520 These methods may or may not 29 00:01:46,680 --> 00:01:49,800 have a default behavior. 30 00:01:50,160 --> 00:01:53,840 Here, let's say that hookMethod 1 has a default behavior. 31 00:01:54,000 --> 00:01:57,160 This means that if the subclass proposes nothing, 32 00:01:57,680 --> 00:02:03,000 hookMethod 1 has a default behavior that functions. 33 00:02:04,240 --> 00:02:06,280 Likewise, we could say 34 00:02:06,440 --> 00:02:09,960 that hookMethod 2 does not have a default behavior. 35 00:02:10,120 --> 00:02:12,840 The subclass must imperatively define one. 36 00:02:13,000 --> 00:02:15,960 As designer of the class, you can choose 37 00:02:16,120 --> 00:02:19,840 whether or not to determine a default behavior. 38 00:02:20,640 --> 00:02:23,760 We'll use printString as a first example. 39 00:02:23,920 --> 00:02:27,640 The idea is that if I send a printString message to an object, 40 00:02:27,800 --> 00:02:31,120 I get a string of characters that represents this object. 41 00:02:31,280 --> 00:02:33,160 Here I have a delay. 42 00:02:34,400 --> 00:02:37,640 I've created a 10-second delay. 43 00:02:38,480 --> 00:02:42,960 If I send a printString message to this delay, 44 00:02:43,120 --> 00:02:47,720 I get a delay and in parentheses, a millisecond value for the delay. 45 00:02:48,200 --> 00:02:52,840 The printString method is implemented in the object class like this. 46 00:02:53,600 --> 00:02:56,640 It sends the message printStringLimitedTo 47 00:02:57,160 --> 00:02:58,560 This implementation 48 00:02:58,720 --> 00:03:02,920 recovers a string of characters that represents 49 00:03:03,080 --> 00:03:04,880 the object. 50 00:03:05,040 --> 00:03:09,360 And if this string of characters is too long, 51 00:03:10,200 --> 00:03:13,800 we can cut it off at a certain limit. 52 00:03:13,960 --> 00:03:17,400 Then at the end, we concatenate with '...etc...' 53 00:03:17,560 --> 00:03:19,880 to say the string is not done. 54 00:03:20,640 --> 00:03:23,600 The important thing here 55 00:03:23,760 --> 00:03:28,120 is that printStringLimitedTo sends a printOn message to self. 56 00:03:28,280 --> 00:03:29,880 This is the method 57 00:03:30,040 --> 00:03:33,400 that will or will not be redefined in the subclasses. 58 00:03:34,040 --> 00:03:37,560 If I look at what printString returns 59 00:03:37,720 --> 00:03:40,120 for a Node and for an Apple, 60 00:03:40,280 --> 00:03:43,800 Node new returns a Node. 61 00:03:44,200 --> 00:03:48,440 This is the printString of the Node class. 62 00:03:49,120 --> 00:03:53,240 And here in Apple, we have the printString of the Apple class. 63 00:03:53,720 --> 00:03:57,000 We see that this behavior and the default behavior 64 00:03:57,160 --> 00:03:59,920 are implemented in the class object. 65 00:04:00,080 --> 00:04:04,320 So the default behavior of printString for any object whatsoever 66 00:04:04,680 --> 00:04:06,000 is one: 67 00:04:06,160 --> 00:04:10,000 Recover the class names. 68 00:04:10,160 --> 00:04:12,840 In this case, Node and Apple. 69 00:04:13,120 --> 00:04:16,720 And two, if the class name begins with a vowel, 70 00:04:17,640 --> 00:04:19,760 we use the prefix "an". 71 00:04:19,920 --> 00:04:23,000 If it starts with a consonant, we use the prefix "a". 72 00:04:23,160 --> 00:04:26,320 This is how we get "a node" and "an apple". 73 00:04:27,880 --> 00:04:30,520 This is the default behavior. 74 00:04:31,120 --> 00:04:34,400 But it is possible to change this default behavior 75 00:04:34,560 --> 00:04:36,280 by refining printOn. 76 00:04:36,720 --> 00:04:38,480 For a delay, 77 00:04:38,640 --> 00:04:41,560 we see that the printString of a delay 78 00:04:41,720 --> 00:04:46,240 starts with the default printOn return. 79 00:04:46,400 --> 00:04:47,640 That is "a Delay." 80 00:04:47,800 --> 00:04:52,720 But afterwards, we can add the delay in milliseconds in parentheses. 81 00:04:52,880 --> 00:04:56,040 This is exactly what the printOn method does. 82 00:04:56,880 --> 00:05:01,080 It starts by asking the superclass for the default printString. 83 00:05:02,160 --> 00:05:05,240 Afterwards, it opens a parentheses 84 00:05:05,560 --> 00:05:08,080 with a preset number of milliseconds, 85 00:05:08,880 --> 00:05:11,240 and then it closes the parentheses. 86 00:05:11,760 --> 00:05:14,720 We just looked at refinement. 87 00:05:15,040 --> 00:05:18,120 The delay class refines the implementation 88 00:05:18,280 --> 00:05:21,520 of the printOn method in the object class. 89 00:05:21,680 --> 00:05:25,200 But a class can also completely redefine behavior. 90 00:05:25,680 --> 00:05:29,880 This is the case for booleans, for example. 91 00:05:30,040 --> 00:05:31,760 If I display false, 92 00:05:31,920 --> 00:05:34,800 it will return false. 93 00:05:34,960 --> 00:05:37,240 We don't have "a false", 94 00:05:37,400 --> 00:05:39,120 simply "false". 95 00:05:39,280 --> 00:05:43,200 For this, we just send the "false" string of characters 96 00:05:43,360 --> 00:05:45,680 in the printOn variables stream. 97 00:05:46,200 --> 00:05:48,080 That's a complete redefinition. 98 00:05:48,240 --> 00:05:51,640 Another example of complete redefinition is intervals. 99 00:05:51,800 --> 00:05:54,120 An interval defines a set of values 100 00:05:54,280 --> 00:05:56,920 situated between a minimum and maximum value. 101 00:05:57,680 --> 00:06:02,680 The interval 1 to 100 is displayed by: (1 to: 100) 102 00:06:04,320 --> 00:06:07,600 The interval 1 to: 100 by: 3 103 00:06:07,840 --> 00:06:10,400 1, 4, and so on, 104 00:06:10,560 --> 00:06:14,720 is displayed in the same manner with the additional "by". 105 00:06:15,680 --> 00:06:18,080 How is this implemented? 106 00:06:18,240 --> 00:06:22,640 The interval class redefines the printOn method 107 00:06:23,120 --> 00:06:26,200 and sends different messages to stream variables. 108 00:06:26,360 --> 00:06:28,600 We start by opening parentheses. 109 00:06:28,760 --> 00:06:31,240 The parentheses here and here. 110 00:06:31,600 --> 00:06:36,560 Then we display the initial value or the first number of the interval, 111 00:06:36,720 --> 00:06:39,360 that is this "1" here, and this "1" here. 112 00:06:39,680 --> 00:06:41,440 Then we write 'to:'. 113 00:06:44,600 --> 00:06:47,640 And we write the final value: "100", 114 00:06:48,520 --> 00:06:49,800 and "100". 115 00:06:50,000 --> 00:06:53,720 If there is a "by" that is different from the default "1", 116 00:06:53,880 --> 00:06:56,800 we write the "a". 117 00:06:59,120 --> 00:07:02,320 And at the end, we close the parentheses. 118 00:07:04,360 --> 00:07:07,000 We saw that printString 119 00:07:07,160 --> 00:07:11,000 uses the Design Pattern template method so that classes 120 00:07:11,160 --> 00:07:15,120 can implement their own textual representation. 121 00:07:15,360 --> 00:07:19,600 Now we'll look at another example, which is object copy. 122 00:07:19,760 --> 00:07:21,120 What does copy do? 123 00:07:21,280 --> 00:07:25,960 It enables you to take an object and create a code from it. 124 00:07:26,840 --> 00:07:29,680 Copying objects is complex. 125 00:07:30,880 --> 00:07:33,120 There can be different strategies. 126 00:07:33,280 --> 00:07:35,200 Each class can decide 127 00:07:35,360 --> 00:07:39,200 what the copy of its instances should look like. 128 00:07:39,720 --> 00:07:43,400 There is a simple template method solution 129 00:07:43,560 --> 00:07:46,520 that uses copy and postCopy. 130 00:07:46,880 --> 00:07:50,560 Copy is a template method and postCopy is a hook. 131 00:07:51,360 --> 00:07:54,200 In the object class there is a copy method. 132 00:07:54,800 --> 00:07:57,640 I'll let you read the commentary. 133 00:07:58,640 --> 00:08:02,920 In this method, we send shallowCopy 134 00:08:03,080 --> 00:08:05,240 as a message to self, 135 00:08:05,400 --> 00:08:08,640 followed by postCopy on the result. 136 00:08:08,920 --> 00:08:12,360 What does shallowCopy do? 137 00:08:12,520 --> 00:08:16,200 It creates a new object that shares all instance variables 138 00:08:16,360 --> 00:08:17,960 with the base object. 139 00:08:18,200 --> 00:08:22,080 We have two objects and their instance variables are the same. 140 00:08:22,240 --> 00:08:26,640 If I modify the instance variable of one object, I modify the other too. 141 00:08:28,880 --> 00:08:32,320 That is the default behavior 142 00:08:34,320 --> 00:08:35,720 of shallowCopy. 143 00:08:35,880 --> 00:08:38,800 Depending on what postCopy does, 144 00:08:38,960 --> 00:08:41,400 variables will or will not be shared. 145 00:08:41,560 --> 00:08:44,240 If postCopy is empty, all variables are shared. 146 00:08:44,400 --> 00:08:48,640 But the classes can decide to put different things into postCopy 147 00:08:48,800 --> 00:08:52,440 in order to share certain variables or nothing at all. 148 00:08:53,040 --> 00:08:55,680 The postCopy default setting shares everything. 149 00:08:55,840 --> 00:08:59,240 It simply returns the current object. 150 00:09:00,440 --> 00:09:04,080 But we could also imagine other applications for postCopy. 151 00:09:04,240 --> 00:09:06,680 For example, in the Bag class. 152 00:09:06,840 --> 00:09:09,600 Bag is a type of collection 153 00:09:09,840 --> 00:09:13,440 and its postCopy method copies its contents. 154 00:09:14,640 --> 00:09:17,520 Thus, a Bag is a contents instance variable, 155 00:09:17,680 --> 00:09:21,080 and the designers of the Bag class decided that 156 00:09:21,240 --> 00:09:22,920 when you copy a Bag, 157 00:09:23,080 --> 00:09:26,000 you don't want to share the contents variable, 158 00:09:26,160 --> 00:09:27,920 you want separate variables. 159 00:09:28,080 --> 00:09:31,960 They have the same initial value but you can modify only one. 160 00:09:33,440 --> 00:09:34,720 Here the idea is: 161 00:09:34,880 --> 00:09:39,440 postCopy is a message sent to copy, or the new object, 162 00:09:41,880 --> 00:09:45,080 which shares all of the instance variables. 163 00:09:45,240 --> 00:09:47,200 If we don't want to share them, 164 00:09:47,360 --> 00:09:50,280 we create new ones and decide upon their value. 165 00:09:50,760 --> 00:09:52,600 Here in my contents variable, 166 00:09:52,760 --> 00:09:55,120 I'll put a copy of the initial contents. 167 00:09:55,280 --> 00:09:57,000 That way I don't share them. 168 00:09:57,160 --> 00:10:00,080 Each copy of my Bag has its own contents. 169 00:10:00,600 --> 00:10:03,400 With the dictionary, we go even further. 170 00:10:03,560 --> 00:10:06,840 A dictionary is a collection of key-value pairs, 171 00:10:07,000 --> 00:10:09,080 or a collection of associations. 172 00:10:09,240 --> 00:10:12,360 Not only do we want to copy the collection... 173 00:10:12,520 --> 00:10:16,000 If we copy a dictionary, we want to copy the collection, 174 00:10:16,160 --> 00:10:19,440 and each dictionary has its own collection of pairs... 175 00:10:19,600 --> 00:10:21,960 But we also want each pair to be different. 176 00:10:22,120 --> 00:10:26,520 So that if I modify one, it won't modify the other side. 177 00:10:26,920 --> 00:10:30,640 To do this, I copy the table, but I also copy 178 00:10:30,800 --> 00:10:32,400 each pair inside. 179 00:10:32,560 --> 00:10:34,720 This is what's going on here. 180 00:10:34,880 --> 00:10:38,640 To conclude, the Design Pattern template method is very common. 181 00:10:39,040 --> 00:10:41,520 It's a sign of good design. 182 00:10:41,720 --> 00:10:45,880 If you do good object design, you'll have lots of template methods. 183 00:10:46,040 --> 00:10:48,560 It's perfectly normal and a good thing. 184 00:10:49,080 --> 00:10:50,920 So don't hesitate to use them. 185 00:10:51,080 --> 00:10:56,040 This technique enables subclasses to define behavior 186 00:10:56,200 --> 00:10:59,640 and partially modify the behavior of the superclass.