﻿1
00:00:00,480 --> 00:00:03,920
今日は前回の講義の続きをします。

2
00:00:04,080 --> 00:00:07,280
前回は小さなメソッドの利点を
説明しました。

3
00:00:07,440 --> 00:00:09,160
今日はいくつかの例をお見せします。

4
00:00:09,320 --> 00:00:12,840
まずは前回の復習をしましょう。

5
00:00:13,000 --> 00:00:15,280
メッセージを送ることは
分岐をもたらすことがあります。

6
00:00:15,440 --> 00:00:19,640
つまり、実際にどの実装が使われるか

7
00:00:19,800 --> 00:00:21,560
表面上明らかでない分岐といえます。

8
00:00:22,040 --> 00:00:25,960
そして Pharo がメッセージのレシーバー
に応じて、どの分岐を辿るか選択します。

9
00:00:26,480 --> 00:00:30,360
クラス階層が分岐の場合分けを定義します。
クラスが多ければ場合分けも増えます。

10
00:00:30,600 --> 00:00:34,360
サブクラスを作ることで
簡単に場合を追加できます。

11
00:00:35,760 --> 00:00:40,480
サブクラスはスーパークラスのコードを
上書きしたり修正することができます。

12
00:00:42,000 --> 00:00:43,920
そして、メッセージを送ることは

13
00:00:44,080 --> 00:00:49,360
サブクラスに振る舞いを変える機会を
与えるということです。

14
00:00:50,520 --> 00:00:54,080
今日は、テンプレートメソッドと呼ばれる
デザインパターンを見てみましょう。

15
00:00:54,240 --> 00:00:56,880
デザインパターンの本に載っています。

16
00:00:57,640 --> 00:00:59,960
テンプレートメソッドとは

17
00:01:00,120 --> 00:01:04,600
あるアルゴリズムの
全体的な振る舞いを定義して、

18
00:01:04,760 --> 00:01:08,800
内部にフックを用意したものです。

19
00:01:08,960 --> 00:01:12,680
そしてフックはサブクラスによって
再定義することができます。

20
00:01:13,840 --> 00:01:16,000
これがアルゴリズムです。

21
00:01:16,320 --> 00:01:19,320
このアルゴリズムは何かをするわけですが
正確に何をするのかはわかりません。

22
00:01:20,280 --> 00:01:25,320
そして hookMethod1 で何かをします。

23
00:01:25,720 --> 00:01:27,080
そしてまた何かをやって

24
00:01:27,240 --> 00:01:29,480
そして hookMethod2 で何かをします。

25
00:01:29,640 --> 00:01:34,200
hoodMethod1 と hookMethod2 は
どちらも完結したメソッドで

26
00:01:34,360 --> 00:01:37,040
サブクラスで再定義されます。

27
00:01:37,600 --> 00:01:41,320
hookMethod1 と 2 のそれぞれについて
2 つの可能性があります。

28
00:01:42,760 --> 00:01:46,520
メソッドがデフォルトの振る舞いを

29
00:01:46,680 --> 00:01:49,800
持っているかどうかです。

30
00:01:50,160 --> 00:01:53,840
ここでは、 hookMethod1 には
デフォルトの振る舞いがあるとしましょう。

31
00:01:54,000 --> 00:01:57,160
つまり、サブクラスが何も定義しなければ

32
00:01:57,680 --> 00:02:03,000
hookMethod1 はデフォルトの振る舞いで
機能するということです。

33
00:02:04,240 --> 00:02:06,280
一方、hookMethod2 は

34
00:02:06,440 --> 00:02:09,960
デフォルトの振る舞いを
持たないとします。

35
00:02:10,120 --> 00:02:12,840
サブクラスが振る舞いを
定義しなければなりません。

36
00:02:13,000 --> 00:02:15,960
クラスの設計者が
デフォルトの振る舞いを

37
00:02:16,120 --> 00:02:19,840
定義するかどうかを選択します。

38
00:02:20,640 --> 00:02:23,760
printString を 1 つ目の例にします。

39
00:02:23,920 --> 00:02:27,640
オブジェクトに
printString メッセージを送ると

40
00:02:27,800 --> 00:02:31,120
そのオブジェクトを表現した
文字列が得られるというものです。

41
00:02:31,280 --> 00:02:33,160
ここにディレイ（Delay）があります。

42
00:02:34,400 --> 00:02:37,640
10 秒のディレイを作りました。

43
00:02:38,480 --> 00:02:42,960
このディレイに
printString メッセージを送ると

44
00:02:43,120 --> 00:02:47,720
「a Delay」に加えて括弧の中に
何ミリ秒かを示す値が表示されます。

45
00:02:48,200 --> 00:02:52,840
printString メソッドは Object クラスで
このように定義されています。

46
00:02:53,600 --> 00:02:56,640
printStringLimitedTo: メッセージを
送ります。


47
00:02:57,160 --> 00:02:58,560
printStringLimitedTo: の実装で

48
00:02:58,720 --> 00:03:02,920
そのオブジェクトを表現する文字列を

49
00:03:03,080 --> 00:03:04,880
得ています。

50
00:03:05,040 --> 00:03:09,360
もしその文字列が長すぎる場合には

51
00:03:10,200 --> 00:03:13,800
適切な長さで切り捨てて

52
00:03:13,960 --> 00:03:17,400
最後に「...etc...」と付け加えて

53
00:03:17,560 --> 00:03:19,880
この文字列は最後まで表示されていない
ことを表します。

54
00:03:20,640 --> 00:03:23,600
ここで重要なことは

55
00:03:23,760 --> 00:03:28,120
printStringLimitedTo: は self に
printOn: メッセージを送ることです。

56
00:03:28,280 --> 00:03:29,880
このメソッドが

57
00:03:30,040 --> 00:03:33,400
サブクラスで再定義されます。
（再定義されないこともあります）

58
00:03:34,040 --> 00:03:37,560
Node や Apple の printString で

59
00:03:37,720 --> 00:03:40,120
何が得られるか見てみると

60
00:03:40,280 --> 00:03:43,800
Node new は 「a Node」を返します。

61
00:03:44,200 --> 00:03:48,440
これが Node クラスの
printString です。

62
00:03:49,120 --> 00:03:53,240
そしてこれが Apple クラスの
printString です。

63
00:03:53,720 --> 00:03:57,000
この振る舞い
デフォルトの振る舞いは

64
00:03:57,160 --> 00:03:59,920
Object クラスで定義されています。

65
00:04:00,080 --> 00:04:04,320
つまり、あらゆるオブジェクトの
printString のデフォルトの振る舞いが

66
00:04:04,680 --> 00:04:06,000
これです。

67
00:04:06,160 --> 00:04:10,000
クラス名を取得します。

68
00:04:10,160 --> 00:04:12,840
この場合は Node と Apple です。

69
00:04:13,120 --> 00:04:16,720
そしてクラス名が母音で始まっていれば

70
00:04:17,640 --> 00:04:19,760
前に「an」を加えて

71
00:04:19,920 --> 00:04:23,000
子音で始まっていれば
「a」にします。

72
00:04:23,160 --> 00:04:26,320
こうすることで「a Node」や
「an Apple」が得られます。

73
00:04:27,880 --> 00:04:30,520
これがデフォルトの振る舞いです。

74
00:04:31,120 --> 00:04:34,400
このデフォルトの振る舞いは

75
00:04:34,560 --> 00:04:36,280
printOn: を再定義することで
変更することができます。

76
00:04:36,720 --> 00:04:38,480
ディレイの場合には

77
00:04:38,640 --> 00:04:41,560
Delay の printString は

78
00:04:41,720 --> 00:04:46,240
デフォルトの printOn: のもので
始まります。

79
00:04:46,400 --> 00:04:47,640
つまり「a Delay」の部分です。

80
00:04:47,800 --> 00:04:52,720
そしてそれに続いて、括弧の中に
ミリ秒の値を加えています。

81
00:04:52,880 --> 00:04:56,040
printOn: メソッドがやっていることを
そのまま説明すると

82
00:04:56,880 --> 00:05:01,080
まず最初にスーパークラスの
デフォルトの printOn: をします。

83
00:05:02,160 --> 00:05:05,240
続いて、括弧を開いて

84
00:05:05,560 --> 00:05:08,080
設定されたミリ秒の値を表示して

85
00:05:08,880 --> 00:05:11,240
そして括弧を閉じます。

86
00:05:11,760 --> 00:05:14,720
このように再定義されています。

87
00:05:15,040 --> 00:05:18,120
Delay クラスは
Object クラスの printOn: メソッドを

88
00:05:18,280 --> 00:05:21,520
修正しています。

89
00:05:21,680 --> 00:05:25,200
あるいは、振る舞いを完全に再定義
することもできます。

90
00:05:25,680 --> 00:05:29,880
例えば、真偽値がそうです。

91
00:05:30,040 --> 00:05:31,760
false を表示すると

92
00:05:31,920 --> 00:05:34,800
「false」が得られます。

93
00:05:34,960 --> 00:05:37,240
「a false」ではなく

94
00:05:37,400 --> 00:05:39,120
単に「false」です。

95
00:05:39,280 --> 00:05:43,200
こうするために、
printOn: では

96
00:05:43,360 --> 00:05:45,680
単に文字列「false」を
ストリームに送っています。

97
00:05:46,200 --> 00:05:48,080
完全に上書きで再定義しています。

98
00:05:48,240 --> 00:05:51,640
上書きでの再定義のもう 1 つの例は
インターバルです。

99
00:05:51,800 --> 00:05:54,120
インターバルは最小値から最大値までの

100
00:05:54,280 --> 00:05:56,920
間にある値の集合です。

101
00:05:57,680 --> 00:06:02,680
1 から 100 までのインターバルは
「(1 to: 100)」と表示されます。

102
00:06:04,320 --> 00:06:07,600
インターバル 1 to: 100 by: 3 も

103
00:06:07,840 --> 00:06:10,400
1、4、と続きますが

104
00:06:10,560 --> 00:06:14,720
by 付きで同じように表示されます。

105
00:06:15,680 --> 00:06:18,080
これがどのように
実装されているかというと

106
00:06:18,240 --> 00:06:22,640
Interval クラスが
printOn: メソッドを再定義して

107
00:06:23,120 --> 00:06:26,200
ストリームに異なるメッセージを
送っています。

108
00:06:26,360 --> 00:06:28,600
まず括弧を開きます。

109
00:06:28,760 --> 00:06:31,240
括弧はここと、ここにあります。

110
00:06:31,600 --> 00:06:36,560
そしてインターバルの
最初の値を表示します。

111
00:06:36,720 --> 00:06:39,360
ここでは、この「1」と
ここでは、この「1」です。

112
00:06:39,680 --> 00:06:41,440
そして「to:」を書きます。

113
00:06:44,600 --> 00:06:47,640
そして最後の値を書きます。
この「100」と

114
00:06:48,520 --> 00:06:49,800
この「100」です。

115
00:06:50,000 --> 00:06:53,720
そして「by」が必要な場合、つまり
デフォルトの 1 以外の場合には

116
00:06:53,880 --> 00:06:56,800
それを書きます。

117
00:06:59,120 --> 00:07:02,320
そして最後に
括弧を閉じます。

118
00:07:04,360 --> 00:07:07,000
以上のように、printString は

119
00:07:07,160 --> 00:07:11,000
デザインパターンの
テンプレートメソッドを使うことで

120
00:07:11,160 --> 00:07:15,120
それぞれのクラスが自分自身の
文字列表現を実装できるようになっています。

121
00:07:15,360 --> 00:07:19,600
もう 1 つの例を見てみましょう。
オブジェクトのコピーです。

122
00:07:19,760 --> 00:07:21,120
copy を使って

123
00:07:21,280 --> 00:07:25,960
あるオブジェクトから
コピーを作ることができます。

124
00:07:26,840 --> 00:07:29,680
オブジェクトのコピーは複雑です。

125
00:07:30,880 --> 00:07:33,120
いくつかのやり方がありますが

126
00:07:33,280 --> 00:07:35,200
インスタンスのコピーが
どうなるべきかを

127
00:07:35,360 --> 00:07:39,200
それぞれのクラスが決めます。

128
00:07:39,720 --> 00:07:43,400
テンプレートメソッドを使った
シンプルな解決策が

129
00:07:43,560 --> 00:07:46,520
copy と postCopy を使う方法です。

130
00:07:46,880 --> 00:07:50,560
copy がテンプレートメソッドで
postCopy がフックです。

131
00:07:51,360 --> 00:07:54,200
copy メソッドは
Object クラスにあります。

132
00:07:54,800 --> 00:07:57,640
コメントを読んでください。

133
00:07:58,640 --> 00:08:02,920
このメソッドでは
shallowCopy メッセージを

134
00:08:03,080 --> 00:08:05,240
self に送って

135
00:08:05,400 --> 00:08:08,640
続いて
結果に postCopy を送ります。

136
00:08:08,920 --> 00:08:12,360
shallowCopy は

137
00:08:12,520 --> 00:08:16,200
元のオブジェクトのインスタンス変数の
内容を共有する

138
00:08:16,360 --> 00:08:17,960
新しいオブジェクトを生成します。

139
00:08:18,200 --> 00:08:22,080
2 つのオブジェクトは
同一のインスタンス変数を持っています。

140
00:08:22,240 --> 00:08:26,640
一方のオブジェクトのインスタンス変数が
指すオブジェクトでの変更操作は

141
00:08:28,880 --> 00:08:32,320
もう一方のオブジェクトの
インスタンス変数からも見えます。

142
00:08:34,320 --> 00:08:35,720
これが shallowCopy の
デフォルトの振る舞いです。

143
00:08:35,880 --> 00:08:38,800
postCopy の定義次第で

144
00:08:38,960 --> 00:08:41,400
変数が同じオブジェクトを共有するかどうか
が決まります。

145
00:08:41,560 --> 00:08:44,240
postCopy が何もしない場合には
全ての変数の参照先は共有されます。

146
00:08:44,400 --> 00:08:48,640
それぞれのクラスが
ある変数は共有して、また別の変数は

147
00:08:48,800 --> 00:08:52,440
共有しないということを
postCopy で決めます。

148
00:08:53,040 --> 00:08:55,680
postCopy のデフォルト動作では
全て共有されます。

149
00:08:55,840 --> 00:08:59,240
デフォルトの postCopy は
そのオブジェクトをそのまま返します。

150
00:09:00,440 --> 00:09:04,080
しかしそれ以外のものもあります。

151
00:09:04,240 --> 00:09:06,680
例えば、Bag クラスです。

152
00:09:06,840 --> 00:09:09,600
Bag は集合の一種ですが

153
00:09:09,840 --> 00:09:13,440
postCopy メソッドはその中身を
コピーします。

154
00:09:14,640 --> 00:09:17,520
Bag には インスタンス変数 contents
がありますが

155
00:09:17,680 --> 00:09:21,080
Bag クラスの設計者は

156
00:09:21,240 --> 00:09:22,920
Bag のコピーを作る時には

157
00:09:23,080 --> 00:09:26,000
インスタンス変数 contents を
共有せずに

158
00:09:26,160 --> 00:09:27,920
別々のオブジェクトを指すようにしました。
双方の contents は

159
00:09:28,080 --> 00:09:31,960
同じ初期値を持っていますが
一方のみを変更することができます。

160
00:09:33,440 --> 00:09:34,720
つまり

161
00:09:34,880 --> 00:09:39,440
postCopy は
新しく作られたコピーに送られます。

162
00:09:41,880 --> 00:09:45,080
コピーのインスタンス変数は
元のオブジェクトと参照を共有しています。


163
00:09:45,240 --> 00:09:47,200
共有したくない場合には

164
00:09:47,360 --> 00:09:50,280
新しく作ります。

165
00:09:50,760 --> 00:09:52,600
ここに 変数 contents がありますが

166
00:09:52,760 --> 00:09:55,120
ここに元のオブジェクトの
コピーを入れます。

167
00:09:55,280 --> 00:09:57,000
こうして共有しないようにします。

168
00:09:57,160 --> 00:10:00,080
それぞれの Bag ごとに contents
の参照先を持っています。

169
00:10:00,600 --> 00:10:03,400
Dictionary（辞書）ではより複雑です。

170
00:10:03,560 --> 00:10:06,840
辞書はキーと値のペアの集合

171
00:10:07,000 --> 00:10:09,080
言い換えると、関連のコレクションです。

172
00:10:09,240 --> 00:10:12,360
辞書のコピーを作成する時には

173
00:10:12,520 --> 00:10:16,000
関連のコレクションをコピーするだけでなく

174
00:10:16,160 --> 00:10:19,440
それぞれの関連も

175
00:10:19,600 --> 00:10:21,960
それぞれの辞書で別のものに
する必要があります。

176
00:10:22,120 --> 00:10:26,520
そうすることで一方の辞書を書き変えても
もう一方には影響しないようにします。

177
00:10:26,920 --> 00:10:30,640
そのためには
テーブルをコピーするだけでなく

178
00:10:30,800 --> 00:10:32,400
その中の各ペアもコピーします。

179
00:10:32,560 --> 00:10:34,720
これが辞書のコピーで
行われていることです。

180
00:10:34,880 --> 00:10:38,640
まとめるとデザインパターンの
テンプレートメソッドはとてもよく使われます。

181
00:10:39,040 --> 00:10:41,520
良い設計の目印です。

182
00:10:41,720 --> 00:10:45,880
良いオブジェクト設計をすれば
たくさんのテンプレートメソッドができます。

183
00:10:46,040 --> 00:10:48,560
それが自然で良い設計です。

184
00:10:49,080 --> 00:10:50,920
テンプレートメソッドを使うことを
躊躇することはありません。

185
00:10:51,080 --> 00:10:56,040
この技術はサブクラスが
振る舞いを定義することで

186
00:10:56,200 --> 00:10:59,640
スーパークラスが定義した振る舞いを
部分的に変更することを可能にするものです。
