﻿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
正しい決定をするのです。
