WEBVTT

00:00:07.120 --> 00:00:12.760 align:middle
こんにちは、このコースでは私は主に
オブジェクト指向プログラミングについて話します。

00:00:13.480 --> 00:00:17.320 align:middle
そしてオブジェクト指向言語でのディスパッチと

00:00:17.480 --> 00:00:20.560 align:middle
遅延束縛について学びます。

00:00:20.720 --> 00:00:24.880 align:middle
このコースでは Pharo を例として使います。

00:00:25.040 --> 00:00:27.880 align:middle
ありがたいことに
Pharo はうまく実装されています。

00:00:28.040 --> 00:00:32.040 align:middle
次のクラスでは、その大きな潜在力のある
一般化について話します。

00:00:32.200 --> 00:00:33.960 align:middle
では始めましょう。

00:00:34.720 --> 00:00:36.160 align:middle
真偽値(Boolean)を見てみましょう。

00:00:37.520 --> 00:00:38.680 align:middle
真偽値は Pharo では

00:00:38.840 --> 00:00:42.920 align:middle
本当に最も基本的なものです。

00:00:43.080 --> 00:00:47.720 align:middle
& や | や not のような
先行評価の真偽値演算子があります。

00:00:47.880 --> 00:00:52.040 align:middle
or: や and: のような遅延演算子は
必要な時に引数を評価します。

00:00:52.200 --> 00:00:57.320 align:middle
条件分岐もあります。
他のコースで見ることになるでしょう。

00:00:57.480 --> 00:01:02.600 align:middle
良く実装されていますが
驚異的なことや特別なことは何もありません。

00:01:02.760 --> 00:01:05.920 align:middle
先週、練習問題を出しました。

00:01:06.080 --> 00:01:07.920 align:middle
3つの質問がありました。

00:01:08.080 --> 00:01:10.400 align:middle
not をどうやって実装するのか

00:01:10.560 --> 00:01:12.000 align:middle
or をどうやって実装するのか

00:01:12.160 --> 00:01:15.760 align:middle
そして最も重要なことですが
これらの練習問題のゴールは何なのか？

00:01:16.560 --> 00:01:20.400 align:middle
最初の2つの問題に答えます。
そして次のコースで

00:01:20.560 --> 00:01:24.000 align:middle
最後の問題に答えます。

00:01:25.880 --> 00:01:28.080 align:middle
練習問題は…

00:01:28.240 --> 00:01:32.560 align:middle
false に not メッセージを投げたら
true が返ってきます。

00:01:32.720 --> 00:01:35.240 align:middle
true に not なら、falseが返ってきます。

00:01:35.400 --> 00:01:38.600 align:middle
オブジェクトがあるとして
どうやってこれを実装しますか？

00:01:38.760 --> 00:01:41.000 align:middle
まずはいくつかヒントをあげます。

00:01:41.160 --> 00:01:43.720 align:middle
正解では条件分岐を使いません。

00:01:44.280 --> 00:01:46.960 align:middle
大部分の人は条件式を使った答えを見つけるでしょう。

00:01:47.120 --> 00:01:50.960 align:middle
しかし、私の答え、Pharo の実装では

00:01:51.120 --> 00:01:53.440 align:middle
全く条件分岐は使いません。

00:01:54.600 --> 00:01:55.960 align:middle
条件式も。

00:01:56.120 --> 00:01:58.640 align:middle
つまり、正解には if はありません。

00:02:00.600 --> 00:02:04.800 align:middle
少し考えてみてください。
何かアイデアはないですか？

00:02:04.960 --> 00:02:09.960 align:middle
普通はこの手のヒントだけで答えは出てきません。

00:02:10.120 --> 00:02:13.840 align:middle
2つ目のヒントです。
答えは3つのクラスを使います。

00:02:14.360 --> 00:02:17.240 align:middle
Boolean クラスがあります。

00:02:17.400 --> 00:02:19.440 align:middle
これは抽象クラスです。

00:02:19.600 --> 00:02:22.760 align:middle
True クラスと False クラスがあります。

00:02:22.920 --> 00:02:28.400 align:middle
真偽値オブジェクトの true は
True のシングルトンインスタンスです。

00:02:28.560 --> 00:02:30.480 align:middle
違いがわかりますか？

00:02:31.040 --> 00:02:35.200 align:middle
true インスタンスは小文字で始まって

00:02:35.360 --> 00:02:40.920 align:middle
False クラスは大文字の F で始まります。

00:02:41.080 --> 00:02:44.000 align:middle
そして false は
False のシングルトンインスタンスです。

00:02:44.160 --> 00:02:46.200 align:middle
ダイアグラムで可視化すると

00:02:46.360 --> 00:02:50.160 align:middle
true は True のインスタンスで
false は False のだと目に見えて解るでしょう。

00:02:50.320 --> 00:02:55.000 align:middle
理屈の上では、このヒントがあれば
答えは明らかな筈です。

00:02:55.160 --> 00:02:57.520 align:middle
実際あなたに解ったかどうか
私には判らないので

00:02:57.680 --> 00:03:00.520 align:middle
もう少し考えていただきます。

00:03:00.680 --> 00:03:03.520 align:middle
答えは最後にします…

00:03:04.720 --> 00:03:07.600 align:middle
今すぐには教えません。
考えてみましょう。

00:03:07.760 --> 00:03:11.320 align:middle
「選択」をオブジェクト指向言語で
どうやって表現しますか？

00:03:12.400 --> 00:03:14.920 align:middle
同じインターフェイス（メソッド）を持つクラスを

00:03:15.080 --> 00:03:18.920 align:middle
いくつか定義して

00:03:19.080 --> 00:03:21.360 align:middle
インスタンスにメッセージを送ることで
選択を表現します。

00:03:21.520 --> 00:03:25.720 align:middle
ここに例があります。
x open と入力すると

00:03:27.240 --> 00:03:29.920 align:middle
x に関連付けられた正しいメソッドを
選択します。

00:03:30.080 --> 00:03:33.720 align:middle
つまり、ファイルであればファイルを開き
ウィンドウであればウィンドウを開き

00:03:33.880 --> 00:03:35.720 align:middle
ツールであればツールを開きます。

00:03:35.880 --> 00:03:40.800 align:middle
つまり x のクラスに基づいて
メソッドが選択されます。

00:03:41.800 --> 00:03:46.520 align:middle
さあ、このヒントでどんな答えが出てきますか？

00:03:48.400 --> 00:03:50.280 align:middle
これと同じように実装するのです。

00:03:51.400 --> 00:03:56.320 align:middle
つまり、False クラスの not メソッドを実装します。

00:03:56.480 --> 00:03:58.560 align:middle
この場合、true を返します。

00:03:58.720 --> 00:04:03.480 align:middle
True クラスの not メソッドを実装します。
false を返します。

00:04:04.440 --> 00:04:06.440 align:middle
ダイアグラムでは、こんな風になります。

00:04:08.200 --> 00:04:11.840 align:middle
この方法では、明示的な条件分岐がないことが
わかるでしょうか？

00:04:12.000 --> 00:04:14.760 align:middle
この場合、if は全く使いません。

00:04:14.920 --> 00:04:16.200 align:middle
どうやって動くのでしょうか？

00:04:17.040 --> 00:04:20.160 align:middle
こんな風に動きます。
not メッセージを送ると

00:04:21.520 --> 00:04:25.600 align:middle
not メソッドをどこから探すでしょうか？
レシーバーのクラスです。

00:04:25.760 --> 00:04:27.640 align:middle
true は True のインスタンスです。

00:04:27.800 --> 00:04:30.640 align:middle
なので、ここのこのメソッドが実行されます。

00:04:30.800 --> 00:04:33.400 align:middle
そして結果は false になります。
ちゃんと動きます。

00:04:33.560 --> 00:04:37.640 align:middle
では false インスタンスに
not メッセージを投げます。

00:04:37.800 --> 00:04:40.040 align:middle
どこを探しますか？ False クラスです。

00:04:40.200 --> 00:04:42.760 align:middle
この not が実行されて
true が返ります。

00:04:42.920 --> 00:04:46.760 align:middle
これで真偽値を実装して

00:04:46.920 --> 00:04:49.680 align:middle
真偽値の否定を2つのメソッドで

00:04:51.560 --> 00:04:53.640 align:middle
条件分岐を使わずに実装しました。

00:04:54.960 --> 00:04:58.800 align:middle
スーパークラスの実装を見ることもできます。

00:04:58.960 --> 00:05:00.840 align:middle
Boolean クラスは抽象クラスです。

00:05:01.000 --> 00:05:04.720 align:middle
2つのサブクラスがあって
サブクラスが必要な演算子を実装しています。

00:05:04.880 --> 00:05:06.600 align:middle
Pharo では

00:05:06.760 --> 00:05:10.080 align:middle
Boolean の 抽象メソッドとして
not を表現しています。

00:05:10.240 --> 00:05:13.040 align:middle
self subclassResponsibility
を使って。

00:05:13.200 --> 00:05:17.440 align:middle
Pharo について言うことで
それを一般化して欲しいのです。

00:05:18.400 --> 00:05:21.000 align:middle
ここまでで

00:05:21.160 --> 00:05:23.520 align:middle
Or の振る舞いをどう表現するか
理解できたはずです。

00:05:23.680 --> 00:05:25.960 align:middle
これを書く時間を与えます。

00:05:26.120 --> 00:05:28.560 align:middle
考え方としては

00:05:28.720 --> 00:05:31.280 align:middle
引数を使ったメソッドを定義して

00:05:31.440 --> 00:05:33.560 align:middle
値に応じて

00:05:33.720 --> 00:05:37.240 align:middle
正しい結果を導きます。

00:05:38.000 --> 00:05:41.240 align:middle
条件分岐を使えばそれで十分だ
と考えることが多いでしょう。

00:05:41.400 --> 00:05:42.720 align:middle
違います。これが要点です。

00:05:42.880 --> 00:05:47.360 align:middle
もう一度言います。
or を実装するのに条件分岐は必要ありません。

00:05:47.520 --> 00:05:51.280 align:middle
考える時間を10秒あげます。

00:05:51.440 --> 00:05:54.160 align:middle
準備してきたはずですよね。

00:05:55.720 --> 00:05:58.960 align:middle
私の答えは、Boolean 抽象クラスに

00:05:59.120 --> 00:06:01.640 align:middle
or を抽象メソッドとして定義します。
結構。

00:06:02.800 --> 00:06:06.800 align:middle
そして False クラスでは
ここに書いた通りです。

00:06:06.960 --> 00:06:10.280 align:middle
レシーバーは False に属しています。
何を返しましょうか？

00:06:11.240 --> 00:06:15.600 align:middle
true であれば、true を返します。false であれば、false。
何であっても、それ自体を返します。

00:06:15.760 --> 00:06:17.880 align:middle
つまり、引数を返します。

00:06:18.600 --> 00:06:22.840 align:middle
ここに False クラスでの
or の実装があります。

00:06:23.000 --> 00:06:25.400 align:middle
引数を返します。

00:06:25.560 --> 00:06:27.240 align:middle
ここでやった通りです。

00:06:29.320 --> 00:06:30.600 align:middle
同様に

00:06:31.960 --> 00:06:34.720 align:middle
True クラスを見ると

00:06:37.200 --> 00:06:38.800 align:middle
ここで説明されています。

00:06:38.960 --> 00:06:43.640 align:middle
true をレシーバーとして or を送ると

00:06:43.800 --> 00:06:45.360 align:middle
レシーバーを返します。

00:06:45.520 --> 00:06:46.840 align:middle
つまり、true を返します。

00:06:48.360 --> 00:06:51.440 align:middle
ここを見ればわかる通り
ここでもまた条件分岐を使っていません。

00:06:51.600 --> 00:06:53.240 align:middle
メッセージ送信を使っただけです。

00:06:55.000 --> 00:06:59.240 align:middle
より綺麗な方法として
Pharo ではどう書かれているでしょうか？

00:06:59.400 --> 00:07:03.480 align:middle
true がメッセージのレシーバーだと知っています。

00:07:03.640 --> 00:07:06.200 align:middle
なので、true と書く代わりに
self と書きます。

00:07:06.360 --> 00:07:09.680 align:middle
定義を読めば
self とあるのを見て

00:07:09.840 --> 00:07:12.480 align:middle
なるほど。
レシーバーが true だから

00:07:12.640 --> 00:07:15.800 align:middle
同じことか
と解るでしょう。

00:07:18.680 --> 00:07:21.560 align:middle
では、もう一度可視化しましょう。

00:07:21.720 --> 00:07:26.960 align:middle
引数 alpha をつけて true オブジェクトに

00:07:27.120 --> 00:07:29.400 align:middle
or メッセージを送ると

00:07:29.560 --> 00:07:33.080 align:middle
or の定義をここから探します。

00:07:33.240 --> 00:07:35.680 align:middle
そして self を返します。
したがって true です。

00:07:35.840 --> 00:07:39.720 align:middle
引数 alpha をつけて or メッセージを送ると

00:07:39.880 --> 00:07:42.640 align:middle
False クラスから探します。

00:07:42.800 --> 00:07:47.280 align:middle
そしてこの実装に辿り着きます。
alpha を返します。

00:07:47.440 --> 00:07:51.040 align:middle
こうして真偽値表を実装します。

00:07:53.440 --> 00:07:55.360 align:middle
覚えておくべきことは

00:07:55.520 --> 00:07:59.480 align:middle
ここで実装した回答では、条件分岐や

00:08:00.160 --> 00:08:03.120 align:middle
ループのような

00:08:03.280 --> 00:08:05.640 align:middle
明示的な条件命令を全く使わないで

00:08:05.800 --> 00:08:08.480 align:middle
レシーバーに決めさせることです。

00:08:08.640 --> 00:08:12.400 align:middle
つまりメッセージを受け取った
Boolean オブジェクトに

00:08:12.560 --> 00:08:14.680 align:middle
正解を見つけてもらうことです。

00:08:14.840 --> 00:08:18.920 align:middle
独裁的に決めてしまうのではなくて

00:08:19.080 --> 00:08:21.480 align:middle
どこか他の場所で見つけるのが原則です。

00:08:21.640 --> 00:08:24.520 align:middle
それが OOP の基本原則です。

00:08:24.680 --> 00:08:28.560 align:middle
このレッスンの最初でほのめかした経験則です。

00:08:28.720 --> 00:08:30.160 align:middle
求めるな、命じよ。

00:08:30.320 --> 00:08:33.400 align:middle
つまり条件分岐を表現するのではなく

00:08:33.560 --> 00:08:35.240 align:middle
命令を与えるのです。

00:08:35.400 --> 00:08:39.680 align:middle
それが OOP の重要な鍵の1つです。

00:08:39.840 --> 00:08:42.640 align:middle
もう1つは
レシーバーに決めさせることです。

00:08:42.800 --> 00:08:46.760 align:middle
レシーバーに命令を与えて
そのレシーバーが自分の知識をカプセル化したまま

00:08:46.920 --> 00:08:48.840 align:middle
正しい決定をするのです。

