1 00:00:07,120 --> 00:00:12,760 こんにちは、このコースでは私は主に オブジェクト指向プログラミングについて話します。 2 00:00:13,480 --> 00:00:17,320 そしてオブジェクト指向言語でのディスパッチと 3 00:00:17,480 --> 00:00:20,560 遅延束縛について学びます。 4 00:00:20,720 --> 00:00:24,880 このコースでは Pharo を例として使います。 5 00:00:25,040 --> 00:00:27,880 ありがたいことに Pharo はうまく実装されています。 6 00:00:28,040 --> 00:00:32,040 次のクラスでは、その大きな潜在力のある 一般化について話します。 7 00:00:32,200 --> 00:00:33,960 では始めましょう。 8 00:00:34,720 --> 00:00:36,160 真偽値(Boolean)を見てみましょう。 9 00:00:37,520 --> 00:00:38,680 真偽値は Pharo では 10 00:00:38,840 --> 00:00:42,920 本当に最も基本的なものです。 11 00:00:43,080 --> 00:00:47,720 & や | や not のような 先行評価の真偽値演算子があります。 12 00:00:47,880 --> 00:00:52,040 or: や and: のような遅延演算子は 必要な時に引数を評価します。 13 00:00:52,200 --> 00:00:57,320 条件分岐もあります。 他のコースで見ることになるでしょう。 14 00:00:57,480 --> 00:01:02,600 良く実装されていますが 驚異的なことや特別なことは何もありません。 15 00:01:02,760 --> 00:01:05,920 先週、練習問題を出しました。 16 00:01:06,080 --> 00:01:07,920 3つの質問がありました。 17 00:01:08,080 --> 00:01:10,400 not をどうやって実装するのか 18 00:01:10,560 --> 00:01:12,000 or をどうやって実装するのか 19 00:01:12,160 --> 00:01:15,760 そして最も重要なことですが これらの練習問題のゴールは何なのか? 20 00:01:16,560 --> 00:01:20,400 最初の2つの問題に答えます。 そして次のコースで 21 00:01:20,560 --> 00:01:24,000 最後の問題に答えます。 22 00:01:25,880 --> 00:01:28,080 練習問題は… 23 00:01:28,240 --> 00:01:32,560 false に not メッセージを投げたら true が返ってきます。 24 00:01:32,720 --> 00:01:35,240 true に not なら、falseが返ってきます。 25 00:01:35,400 --> 00:01:38,600 オブジェクトがあるとして どうやってこれを実装しますか? 26 00:01:38,760 --> 00:01:41,000 まずはいくつかヒントをあげます。 27 00:01:41,160 --> 00:01:43,720 正解では条件分岐を使いません。 28 00:01:44,280 --> 00:01:46,960 大部分の人は条件式を使った答えを見つけるでしょう。 29 00:01:47,120 --> 00:01:50,960 しかし、私の答え、Pharo の実装では 30 00:01:51,120 --> 00:01:53,440 全く条件分岐は使いません。 31 00:01:54,600 --> 00:01:55,960 条件式も。 32 00:01:56,120 --> 00:01:58,640 つまり、正解には if はありません。 33 00:02:00,600 --> 00:02:04,800 少し考えてみてください。 何かアイデアはないですか? 34 00:02:04,960 --> 00:02:09,960 普通はこの手のヒントだけで答えは出てきません。 35 00:02:10,120 --> 00:02:13,840 2つ目のヒントです。 答えは3つのクラスを使います。 36 00:02:14,360 --> 00:02:17,240 Boolean クラスがあります。 37 00:02:17,400 --> 00:02:19,440 これは抽象クラスです。 38 00:02:19,600 --> 00:02:22,760 True クラスと False クラスがあります。 39 00:02:22,920 --> 00:02:28,400 真偽値オブジェクトの true は True のシングルトンインスタンスです。 40 00:02:28,560 --> 00:02:30,480 違いがわかりますか? 41 00:02:31,040 --> 00:02:35,200 true インスタンスは小文字で始まって 42 00:02:35,360 --> 00:02:40,920 False クラスは大文字の F で始まります。 43 00:02:41,080 --> 00:02:44,000 そして false は False のシングルトンインスタンスです。 44 00:02:44,160 --> 00:02:46,200 ダイアグラムで可視化すると 45 00:02:46,360 --> 00:02:50,160 true は True のインスタンスで false は False のだと目に見えて解るでしょう。 46 00:02:50,320 --> 00:02:55,000 理屈の上では、このヒントがあれば 答えは明らかな筈です。 47 00:02:55,160 --> 00:02:57,520 実際あなたに解ったかどうか 私には判らないので 48 00:02:57,680 --> 00:03:00,520 もう少し考えていただきます。 49 00:03:00,680 --> 00:03:03,520 答えは最後にします… 50 00:03:04,720 --> 00:03:07,600 今すぐには教えません。 考えてみましょう。 51 00:03:07,760 --> 00:03:11,320 「選択」をオブジェクト指向言語で どうやって表現しますか? 52 00:03:12,400 --> 00:03:14,920 同じインターフェイス(メソッド)を持つクラスを 53 00:03:15,080 --> 00:03:18,920 いくつか定義して 54 00:03:19,080 --> 00:03:21,360 インスタンスにメッセージを送ることで 選択を表現します。 55 00:03:21,520 --> 00:03:25,720 ここに例があります。 x open と入力すると 56 00:03:27,240 --> 00:03:29,920 x に関連付けられた正しいメソッドを 選択します。 57 00:03:30,080 --> 00:03:33,720 つまり、ファイルであればファイルを開き ウィンドウであればウィンドウを開き 58 00:03:33,880 --> 00:03:35,720 ツールであればツールを開きます。 59 00:03:35,880 --> 00:03:40,800 つまり x のクラスに基づいて メソッドが選択されます。 60 00:03:41,800 --> 00:03:46,520 さあ、このヒントでどんな答えが出てきますか? 61 00:03:48,400 --> 00:03:50,280 これと同じように実装するのです。 62 00:03:51,400 --> 00:03:56,320 つまり、False クラスの not メソッドを実装します。 63 00:03:56,480 --> 00:03:58,560 この場合、true を返します。 64 00:03:58,720 --> 00:04:03,480 True クラスの not メソッドを実装します。 false を返します。 65 00:04:04,440 --> 00:04:06,440 ダイアグラムでは、こんな風になります。 66 00:04:08,200 --> 00:04:11,840 この方法では、明示的な条件分岐がないことが わかるでしょうか? 67 00:04:12,000 --> 00:04:14,760 この場合、if は全く使いません。 68 00:04:14,920 --> 00:04:16,200 どうやって動くのでしょうか? 69 00:04:17,040 --> 00:04:20,160 こんな風に動きます。 not メッセージを送ると 70 00:04:21,520 --> 00:04:25,600 not メソッドをどこから探すでしょうか? レシーバーのクラスです。 71 00:04:25,760 --> 00:04:27,640 true は True のインスタンスです。 72 00:04:27,800 --> 00:04:30,640 なので、ここのこのメソッドが実行されます。 73 00:04:30,800 --> 00:04:33,400 そして結果は false になります。 ちゃんと動きます。 74 00:04:33,560 --> 00:04:37,640 では false インスタンスに not メッセージを投げます。 75 00:04:37,800 --> 00:04:40,040 どこを探しますか? False クラスです。 76 00:04:40,200 --> 00:04:42,760 この not が実行されて true が返ります。 77 00:04:42,920 --> 00:04:46,760 これで真偽値を実装して 78 00:04:46,920 --> 00:04:49,680 真偽値の否定を2つのメソッドで 79 00:04:51,560 --> 00:04:53,640 条件分岐を使わずに実装しました。 80 00:04:54,960 --> 00:04:58,800 スーパークラスの実装を見ることもできます。 81 00:04:58,960 --> 00:05:00,840 Boolean クラスは抽象クラスです。 82 00:05:01,000 --> 00:05:04,720 2つのサブクラスがあって サブクラスが必要な演算子を実装しています。 83 00:05:04,880 --> 00:05:06,600 Pharo では 84 00:05:06,760 --> 00:05:10,080 Boolean の 抽象メソッドとして not を表現しています。 85 00:05:10,240 --> 00:05:13,040 self subclassResponsibility を使って。 86 00:05:13,200 --> 00:05:17,440 Pharo について言うことで それを一般化して欲しいのです。 87 00:05:18,400 --> 00:05:21,000 ここまでで 88 00:05:21,160 --> 00:05:23,520 Or の振る舞いをどう表現するか 理解できたはずです。 89 00:05:23,680 --> 00:05:25,960 これを書く時間を与えます。 90 00:05:26,120 --> 00:05:28,560 考え方としては 91 00:05:28,720 --> 00:05:31,280 引数を使ったメソッドを定義して 92 00:05:31,440 --> 00:05:33,560 値に応じて 93 00:05:33,720 --> 00:05:37,240 正しい結果を導きます。 94 00:05:38,000 --> 00:05:41,240 条件分岐を使えばそれで十分だ と考えることが多いでしょう。 95 00:05:41,400 --> 00:05:42,720 違います。これが要点です。 96 00:05:42,880 --> 00:05:47,360 もう一度言います。 or を実装するのに条件分岐は必要ありません。 97 00:05:47,520 --> 00:05:51,280 考える時間を10秒あげます。 98 00:05:51,440 --> 00:05:54,160 準備してきたはずですよね。 99 00:05:55,720 --> 00:05:58,960 私の答えは、Boolean 抽象クラスに 100 00:05:59,120 --> 00:06:01,640 or を抽象メソッドとして定義します。 結構。 101 00:06:02,800 --> 00:06:06,800 そして False クラスでは ここに書いた通りです。 102 00:06:06,960 --> 00:06:10,280 レシーバーは False に属しています。 何を返しましょうか? 103 00:06:11,240 --> 00:06:15,600 true であれば、true を返します。false であれば、false。 何であっても、それ自体を返します。 104 00:06:15,760 --> 00:06:17,880 つまり、引数を返します。 105 00:06:18,600 --> 00:06:22,840 ここに False クラスでの or の実装があります。 106 00:06:23,000 --> 00:06:25,400 引数を返します。 107 00:06:25,560 --> 00:06:27,240 ここでやった通りです。 108 00:06:29,320 --> 00:06:30,600 同様に 109 00:06:31,960 --> 00:06:34,720 True クラスを見ると 110 00:06:37,200 --> 00:06:38,800 ここで説明されています。 111 00:06:38,960 --> 00:06:43,640 true をレシーバーとして or を送ると 112 00:06:43,800 --> 00:06:45,360 レシーバーを返します。 113 00:06:45,520 --> 00:06:46,840 つまり、true を返します。 114 00:06:48,360 --> 00:06:51,440 ここを見ればわかる通り ここでもまた条件分岐を使っていません。 115 00:06:51,600 --> 00:06:53,240 メッセージ送信を使っただけです。 116 00:06:55,000 --> 00:06:59,240 より綺麗な方法として Pharo ではどう書かれているでしょうか? 117 00:06:59,400 --> 00:07:03,480 true がメッセージのレシーバーだと知っています。 118 00:07:03,640 --> 00:07:06,200 なので、true と書く代わりに self と書きます。 119 00:07:06,360 --> 00:07:09,680 定義を読めば self とあるのを見て 120 00:07:09,840 --> 00:07:12,480 なるほど。 レシーバーが true だから 121 00:07:12,640 --> 00:07:15,800 同じことか と解るでしょう。 122 00:07:18,680 --> 00:07:21,560 では、もう一度可視化しましょう。 123 00:07:21,720 --> 00:07:26,960 引数 alpha をつけて true オブジェクトに 124 00:07:27,120 --> 00:07:29,400 or メッセージを送ると 125 00:07:29,560 --> 00:07:33,080 or の定義をここから探します。 126 00:07:33,240 --> 00:07:35,680 そして self を返します。 したがって true です。 127 00:07:35,840 --> 00:07:39,720 引数 alpha をつけて or メッセージを送ると 128 00:07:39,880 --> 00:07:42,640 False クラスから探します。 129 00:07:42,800 --> 00:07:47,280 そしてこの実装に辿り着きます。 alpha を返します。 130 00:07:47,440 --> 00:07:51,040 こうして真偽値表を実装します。 131 00:07:53,440 --> 00:07:55,360 覚えておくべきことは 132 00:07:55,520 --> 00:07:59,480 ここで実装した回答では、条件分岐や 133 00:08:00,160 --> 00:08:03,120 ループのような 134 00:08:03,280 --> 00:08:05,640 明示的な条件命令を全く使わないで 135 00:08:05,800 --> 00:08:08,480 レシーバーに決めさせることです。 136 00:08:08,640 --> 00:08:12,400 つまりメッセージを受け取った Boolean オブジェクトに 137 00:08:12,560 --> 00:08:14,680 正解を見つけてもらうことです。 138 00:08:14,840 --> 00:08:18,920 独裁的に決めてしまうのではなくて 139 00:08:19,080 --> 00:08:21,480 どこか他の場所で見つけるのが原則です。 140 00:08:21,640 --> 00:08:24,520 それが OOP の基本原則です。 141 00:08:24,680 --> 00:08:28,560 このレッスンの最初でほのめかした経験則です。 142 00:08:28,720 --> 00:08:30,160 求めるな、命じよ。 143 00:08:30,320 --> 00:08:33,400 つまり条件分岐を表現するのではなく 144 00:08:33,560 --> 00:08:35,240 命令を与えるのです。 145 00:08:35,400 --> 00:08:39,680 それが OOP の重要な鍵の1つです。 146 00:08:39,840 --> 00:08:42,640 もう1つは レシーバーに決めさせることです。 147 00:08:42,800 --> 00:08:46,760 レシーバーに命令を与えて そのレシーバーが自分の知識をカプセル化したまま 148 00:08:46,920 --> 00:08:48,840 正しい決定をするのです。