WEBVTT

00:00:00.480 --> 00:00:03.920 align:middle
今日は前回の講義の続きをします。

00:00:04.080 --> 00:00:07.280 align:middle
前回は小さなメソッドの利点を
説明しました。

00:00:07.440 --> 00:00:09.160 align:middle
今日はいくつかの例をお見せします。

00:00:09.320 --> 00:00:12.840 align:middle
まずは前回の復習をしましょう。

00:00:13.000 --> 00:00:15.280 align:middle
メッセージを送ることは
分岐をもたらすことがあります。

00:00:15.440 --> 00:00:19.640 align:middle
つまり、実際にどの実装が使われるか

00:00:19.800 --> 00:00:21.560 align:middle
表面上明らかでない分岐といえます。

00:00:22.040 --> 00:00:25.960 align:middle
そして Pharo がメッセージのレシーバー
に応じて、どの分岐を辿るか選択します。

00:00:26.480 --> 00:00:30.360 align:middle
クラス階層が分岐の場合分けを定義します。
クラスが多ければ場合分けも増えます。

00:00:30.600 --> 00:00:34.360 align:middle
サブクラスを作ることで
簡単に場合を追加できます。

00:00:35.760 --> 00:00:40.480 align:middle
サブクラスはスーパークラスのコードを
上書きしたり修正することができます。

00:00:42.000 --> 00:00:43.920 align:middle
そして、メッセージを送ることは

00:00:44.080 --> 00:00:49.360 align:middle
サブクラスに振る舞いを変える機会を
与えるということです。

00:00:50.520 --> 00:00:54.080 align:middle
今日は、テンプレートメソッドと呼ばれる
デザインパターンを見てみましょう。

00:00:54.240 --> 00:00:56.880 align:middle
デザインパターンの本に載っています。

00:00:57.640 --> 00:00:59.960 align:middle
テンプレートメソッドとは

00:01:00.120 --> 00:01:04.600 align:middle
あるアルゴリズムの
全体的な振る舞いを定義して、

00:01:04.760 --> 00:01:08.800 align:middle
内部にフックを用意したものです。

00:01:08.960 --> 00:01:12.680 align:middle
そしてフックはサブクラスによって
再定義することができます。

00:01:13.840 --> 00:01:16.000 align:middle
これがアルゴリズムです。

00:01:16.320 --> 00:01:19.320 align:middle
このアルゴリズムは何かをするわけですが
正確に何をするのかはわかりません。

00:01:20.280 --> 00:01:25.320 align:middle
そして hookMethod1 で何かをします。

00:01:25.720 --> 00:01:27.080 align:middle
そしてまた何かをやって

00:01:27.240 --> 00:01:29.480 align:middle
そして hookMethod2 で何かをします。

00:01:29.640 --> 00:01:34.200 align:middle
hoodMethod1 と hookMethod2 は
どちらも完結したメソッドで

00:01:34.360 --> 00:01:37.040 align:middle
サブクラスで再定義されます。

00:01:37.600 --> 00:01:41.320 align:middle
hookMethod1 と 2 のそれぞれについて
2 つの可能性があります。

00:01:42.760 --> 00:01:46.520 align:middle
メソッドがデフォルトの振る舞いを

00:01:46.680 --> 00:01:49.800 align:middle
持っているかどうかです。

00:01:50.160 --> 00:01:53.840 align:middle
ここでは、 hookMethod1 には
デフォルトの振る舞いがあるとしましょう。

00:01:54.000 --> 00:01:57.160 align:middle
つまり、サブクラスが何も定義しなければ

00:01:57.680 --> 00:02:03.000 align:middle
hookMethod1 はデフォルトの振る舞いで
機能するということです。

00:02:04.240 --> 00:02:06.280 align:middle
一方、hookMethod2 は

00:02:06.440 --> 00:02:09.960 align:middle
デフォルトの振る舞いを
持たないとします。

00:02:10.120 --> 00:02:12.840 align:middle
サブクラスが振る舞いを
定義しなければなりません。

00:02:13.000 --> 00:02:15.960 align:middle
クラスの設計者が
デフォルトの振る舞いを

00:02:16.120 --> 00:02:19.840 align:middle
定義するかどうかを選択します。

00:02:20.640 --> 00:02:23.760 align:middle
printString を 1 つ目の例にします。

00:02:23.920 --> 00:02:27.640 align:middle
オブジェクトに
printString メッセージを送ると

00:02:27.800 --> 00:02:31.120 align:middle
そのオブジェクトを表現した
文字列が得られるというものです。

00:02:31.280 --> 00:02:33.160 align:middle
ここにディレイ（Delay）があります。

00:02:34.400 --> 00:02:37.640 align:middle
10 秒のディレイを作りました。

00:02:38.480 --> 00:02:42.960 align:middle
このディレイに
printString メッセージを送ると

00:02:43.120 --> 00:02:47.720 align:middle
「a Delay」に加えて括弧の中に
何ミリ秒かを示す値が表示されます。

00:02:48.200 --> 00:02:52.840 align:middle
printString メソッドは Object クラスで
このように定義されています。

00:02:53.600 --> 00:02:56.640 align:middle
printStringLimitedTo: メッセージを
送ります。

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

00:02:58.720 --> 00:03:02.920 align:middle
そのオブジェクトを表現する文字列を

00:03:03.080 --> 00:03:04.880 align:middle
得ています。

00:03:05.040 --> 00:03:09.360 align:middle
もしその文字列が長すぎる場合には

00:03:10.200 --> 00:03:13.800 align:middle
適切な長さで切り捨てて

00:03:13.960 --> 00:03:17.400 align:middle
最後に「...etc...」と付け加えて

00:03:17.560 --> 00:03:19.880 align:middle
この文字列は最後まで表示されていない
ことを表します。

00:03:20.640 --> 00:03:23.600 align:middle
ここで重要なことは

00:03:23.760 --> 00:03:28.120 align:middle
printStringLimitedTo: は self に
printOn: メッセージを送ることです。

00:03:28.280 --> 00:03:29.880 align:middle
このメソッドが

00:03:30.040 --> 00:03:33.400 align:middle
サブクラスで再定義されます。
（再定義されないこともあります）

00:03:34.040 --> 00:03:37.560 align:middle
Node や Apple の printString で

00:03:37.720 --> 00:03:40.120 align:middle
何が得られるか見てみると

00:03:40.280 --> 00:03:43.800 align:middle
Node new は 「a Node」を返します。

00:03:44.200 --> 00:03:48.440 align:middle
これが Node クラスの
printString です。

00:03:49.120 --> 00:03:53.240 align:middle
そしてこれが Apple クラスの
printString です。

00:03:53.720 --> 00:03:57.000 align:middle
この振る舞い
デフォルトの振る舞いは

00:03:57.160 --> 00:03:59.920 align:middle
Object クラスで定義されています。

00:04:00.080 --> 00:04:04.320 align:middle
つまり、あらゆるオブジェクトの
printString のデフォルトの振る舞いが

00:04:04.680 --> 00:04:06.000 align:middle
これです。

00:04:06.160 --> 00:04:10.000 align:middle
クラス名を取得します。

00:04:10.160 --> 00:04:12.840 align:middle
この場合は Node と Apple です。

00:04:13.120 --> 00:04:16.720 align:middle
そしてクラス名が母音で始まっていれば

00:04:17.640 --> 00:04:19.760 align:middle
前に「an」を加えて

00:04:19.920 --> 00:04:23.000 align:middle
子音で始まっていれば
「a」にします。

00:04:23.160 --> 00:04:26.320 align:middle
こうすることで「a Node」や
「an Apple」が得られます。

00:04:27.880 --> 00:04:30.520 align:middle
これがデフォルトの振る舞いです。

00:04:31.120 --> 00:04:34.400 align:middle
このデフォルトの振る舞いは

00:04:34.560 --> 00:04:36.280 align:middle
printOn: を再定義することで
変更することができます。

00:04:36.720 --> 00:04:38.480 align:middle
ディレイの場合には

00:04:38.640 --> 00:04:41.560 align:middle
Delay の printString は

00:04:41.720 --> 00:04:46.240 align:middle
デフォルトの printOn: のもので
始まります。

00:04:46.400 --> 00:04:47.640 align:middle
つまり「a Delay」の部分です。

00:04:47.800 --> 00:04:52.720 align:middle
そしてそれに続いて、括弧の中に
ミリ秒の値を加えています。

00:04:52.880 --> 00:04:56.040 align:middle
printOn: メソッドがやっていることを
そのまま説明すると

00:04:56.880 --> 00:05:01.080 align:middle
まず最初にスーパークラスの
デフォルトの printOn: をします。

00:05:02.160 --> 00:05:05.240 align:middle
続いて、括弧を開いて

00:05:05.560 --> 00:05:08.080 align:middle
設定されたミリ秒の値を表示して

00:05:08.880 --> 00:05:11.240 align:middle
そして括弧を閉じます。

00:05:11.760 --> 00:05:14.720 align:middle
このように再定義されています。

00:05:15.040 --> 00:05:18.120 align:middle
Delay クラスは
Object クラスの printOn: メソッドを

00:05:18.280 --> 00:05:21.520 align:middle
修正しています。

00:05:21.680 --> 00:05:25.200 align:middle
あるいは、振る舞いを完全に再定義
することもできます。

00:05:25.680 --> 00:05:29.880 align:middle
例えば、真偽値がそうです。

00:05:30.040 --> 00:05:31.760 align:middle
false を表示すると

00:05:31.920 --> 00:05:34.800 align:middle
「false」が得られます。

00:05:34.960 --> 00:05:37.240 align:middle
「a false」ではなく

00:05:37.400 --> 00:05:39.120 align:middle
単に「false」です。

00:05:39.280 --> 00:05:43.200 align:middle
こうするために、
printOn: では

00:05:43.360 --> 00:05:45.680 align:middle
単に文字列「false」を
ストリームに送っています。

00:05:46.200 --> 00:05:48.080 align:middle
完全に上書きで再定義しています。

00:05:48.240 --> 00:05:51.640 align:middle
上書きでの再定義のもう 1 つの例は
インターバルです。

00:05:51.800 --> 00:05:54.120 align:middle
インターバルは最小値から最大値までの

00:05:54.280 --> 00:05:56.920 align:middle
間にある値の集合です。

00:05:57.680 --> 00:06:02.680 align:middle
1 から 100 までのインターバルは
「(1 to: 100)」と表示されます。

00:06:04.320 --> 00:06:07.600 align:middle
インターバル 1 to: 100 by: 3 も

00:06:07.840 --> 00:06:10.400 align:middle
1、4、と続きますが

00:06:10.560 --> 00:06:14.720 align:middle
by 付きで同じように表示されます。

00:06:15.680 --> 00:06:18.080 align:middle
これがどのように
実装されているかというと

00:06:18.240 --> 00:06:22.640 align:middle
Interval クラスが
printOn: メソッドを再定義して

00:06:23.120 --> 00:06:26.200 align:middle
ストリームに異なるメッセージを
送っています。

00:06:26.360 --> 00:06:28.600 align:middle
まず括弧を開きます。

00:06:28.760 --> 00:06:31.240 align:middle
括弧はここと、ここにあります。

00:06:31.600 --> 00:06:36.560 align:middle
そしてインターバルの
最初の値を表示します。

00:06:36.720 --> 00:06:39.360 align:middle
ここでは、この「1」と
ここでは、この「1」です。

00:06:39.680 --> 00:06:41.440 align:middle
そして「to:」を書きます。

00:06:44.600 --> 00:06:47.640 align:middle
そして最後の値を書きます。
この「100」と

00:06:48.520 --> 00:06:49.800 align:middle
この「100」です。

00:06:50.000 --> 00:06:53.720 align:middle
そして「by」が必要な場合、つまり
デフォルトの 1 以外の場合には

00:06:53.880 --> 00:06:56.800 align:middle
それを書きます。

00:06:59.120 --> 00:07:02.320 align:middle
そして最後に
括弧を閉じます。

00:07:04.360 --> 00:07:07.000 align:middle
以上のように、printString は

00:07:07.160 --> 00:07:11.000 align:middle
デザインパターンの
テンプレートメソッドを使うことで

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

00:07:15.360 --> 00:07:19.600 align:middle
もう 1 つの例を見てみましょう。
オブジェクトのコピーです。

00:07:19.760 --> 00:07:21.120 align:middle
copy を使って

00:07:21.280 --> 00:07:25.960 align:middle
あるオブジェクトから
コピーを作ることができます。

00:07:26.840 --> 00:07:29.680 align:middle
オブジェクトのコピーは複雑です。

00:07:30.880 --> 00:07:33.120 align:middle
いくつかのやり方がありますが

00:07:33.280 --> 00:07:35.200 align:middle
インスタンスのコピーが
どうなるべきかを

00:07:35.360 --> 00:07:39.200 align:middle
それぞれのクラスが決めます。

00:07:39.720 --> 00:07:43.400 align:middle
テンプレートメソッドを使った
シンプルな解決策が

00:07:43.560 --> 00:07:46.520 align:middle
copy と postCopy を使う方法です。

00:07:46.880 --> 00:07:50.560 align:middle
copy がテンプレートメソッドで
postCopy がフックです。

00:07:51.360 --> 00:07:54.200 align:middle
copy メソッドは
Object クラスにあります。

00:07:54.800 --> 00:07:57.640 align:middle
コメントを読んでください。

00:07:58.640 --> 00:08:02.920 align:middle
このメソッドでは
shallowCopy メッセージを

00:08:03.080 --> 00:08:05.240 align:middle
self に送って

00:08:05.400 --> 00:08:08.640 align:middle
続いて
結果に postCopy を送ります。

00:08:08.920 --> 00:08:12.360 align:middle
shallowCopy は

00:08:12.520 --> 00:08:16.200 align:middle
元のオブジェクトのインスタンス変数の
内容を共有する

00:08:16.360 --> 00:08:17.960 align:middle
新しいオブジェクトを生成します。

00:08:18.200 --> 00:08:22.080 align:middle
2 つのオブジェクトは
同一のインスタンス変数を持っています。

00:08:22.240 --> 00:08:26.640 align:middle
一方のオブジェクトのインスタンス変数が
指すオブジェクトでの変更操作は

00:08:28.880 --> 00:08:32.320 align:middle
もう一方のオブジェクトの
インスタンス変数からも見えます。

00:08:34.320 --> 00:08:35.720 align:middle
これが shallowCopy の
デフォルトの振る舞いです。

00:08:35.880 --> 00:08:38.800 align:middle
postCopy の定義次第で

00:08:38.960 --> 00:08:41.400 align:middle
変数が同じオブジェクトを共有するかどうか
が決まります。

00:08:41.560 --> 00:08:44.240 align:middle
postCopy が何もしない場合には
全ての変数の参照先は共有されます。

00:08:44.400 --> 00:08:48.640 align:middle
それぞれのクラスが
ある変数は共有して、また別の変数は

00:08:48.800 --> 00:08:52.440 align:middle
共有しないということを
postCopy で決めます。

00:08:53.040 --> 00:08:55.680 align:middle
postCopy のデフォルト動作では
全て共有されます。

00:08:55.840 --> 00:08:59.240 align:middle
デフォルトの postCopy は
そのオブジェクトをそのまま返します。

00:09:00.440 --> 00:09:04.080 align:middle
しかしそれ以外のものもあります。

00:09:04.240 --> 00:09:06.680 align:middle
例えば、Bag クラスです。

00:09:06.840 --> 00:09:09.600 align:middle
Bag は集合の一種ですが

00:09:09.840 --> 00:09:13.440 align:middle
postCopy メソッドはその中身を
コピーします。

00:09:14.640 --> 00:09:17.520 align:middle
Bag には インスタンス変数 contents
がありますが

00:09:17.680 --> 00:09:21.080 align:middle
Bag クラスの設計者は

00:09:21.240 --> 00:09:22.920 align:middle
Bag のコピーを作る時には

00:09:23.080 --> 00:09:26.000 align:middle
インスタンス変数 contents を
共有せずに

00:09:26.160 --> 00:09:27.920 align:middle
別々のオブジェクトを指すようにしました。
双方の contents は

00:09:28.080 --> 00:09:31.960 align:middle
同じ初期値を持っていますが
一方のみを変更することができます。

00:09:33.440 --> 00:09:34.720 align:middle
つまり

00:09:34.880 --> 00:09:39.440 align:middle
postCopy は
新しく作られたコピーに送られます。

00:09:41.880 --> 00:09:45.080 align:middle
コピーのインスタンス変数は
元のオブジェクトと参照を共有しています。

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

00:09:47.360 --> 00:09:50.280 align:middle
新しく作ります。

00:09:50.760 --> 00:09:52.600 align:middle
ここに 変数 contents がありますが

00:09:52.760 --> 00:09:55.120 align:middle
ここに元のオブジェクトの
コピーを入れます。

00:09:55.280 --> 00:09:57.000 align:middle
こうして共有しないようにします。

00:09:57.160 --> 00:10:00.080 align:middle
それぞれの Bag ごとに contents
の参照先を持っています。

00:10:00.600 --> 00:10:03.400 align:middle
Dictionary（辞書）ではより複雑です。

00:10:03.560 --> 00:10:06.840 align:middle
辞書はキーと値のペアの集合

00:10:07.000 --> 00:10:09.080 align:middle
言い換えると、関連のコレクションです。

00:10:09.240 --> 00:10:12.360 align:middle
辞書のコピーを作成する時には

00:10:12.520 --> 00:10:16.000 align:middle
関連のコレクションをコピーするだけでなく

00:10:16.160 --> 00:10:19.440 align:middle
それぞれの関連も

00:10:19.600 --> 00:10:21.960 align:middle
それぞれの辞書で別のものに
する必要があります。

00:10:22.120 --> 00:10:26.520 align:middle
そうすることで一方の辞書を書き変えても
もう一方には影響しないようにします。

00:10:26.920 --> 00:10:30.640 align:middle
そのためには
テーブルをコピーするだけでなく

00:10:30.800 --> 00:10:32.400 align:middle
その中の各ペアもコピーします。

00:10:32.560 --> 00:10:34.720 align:middle
これが辞書のコピーで
行われていることです。

00:10:34.880 --> 00:10:38.640 align:middle
まとめるとデザインパターンの
テンプレートメソッドはとてもよく使われます。

00:10:39.040 --> 00:10:41.520 align:middle
良い設計の目印です。

00:10:41.720 --> 00:10:45.880 align:middle
良いオブジェクト設計をすれば
たくさんのテンプレートメソッドができます。

00:10:46.040 --> 00:10:48.560 align:middle
それが自然で良い設計です。

00:10:49.080 --> 00:10:50.920 align:middle
テンプレートメソッドを使うことを
躊躇することはありません。

00:10:51.080 --> 00:10:56.040 align:middle
この技術はサブクラスが
振る舞いを定義することで

00:10:56.200 --> 00:10:59.640 align:middle
スーパークラスが定義した振る舞いを
部分的に変更することを可能にするものです。

