WEBVTT

00:00:00.720 --> 00:00:06.000 align:middle
みなさん、こんにちは。
反 if キャンペーンについてお話します。

00:00:06.480 --> 00:00:09.480 align:middle
特に、説明したいのは

00:00:09.920 --> 00:00:13.720 align:middle
返り値の nil や nil チェックが
いかに良くないかです。

00:00:13.920 --> 00:00:18.520 align:middle
ここに例題コードがあります。
オブジェクト的ではありません。

00:00:19.040 --> 00:00:21.680 align:middle
メソッドの引数は動物です。

00:00:21.880 --> 00:00:24.680 align:middle
動作はその動物によって変わります。

00:00:24.880 --> 00:00:30.560 align:middle
例えば、犬に尻尾を振らせたり
アヒルにガーガー鳴かせたりします。

00:00:31.000 --> 00:00:33.440 align:middle
猫には他のことをさせます。

00:00:34.040 --> 00:00:38.080 align:middle
さて、どうして if 文を使うのは
問題があるのでしょう？

00:00:39.120 --> 00:00:43.800 align:middle
特に、レシーバーの型を
検査する場合です。

00:00:45.080 --> 00:00:49.200 align:middle
例えば、ここに新しい動物を
追加したいとします。

00:00:49.360 --> 00:00:53.400 align:middle
当てはまる可能性がありそうな
if 文を探して

00:00:53.680 --> 00:00:56.880 align:middle
プロジェクトコード全体を
チェックする必要があるでしょう。

00:00:57.040 --> 00:01:01.280 align:middle
プロジェクトを通して大量のコードを
書き換えなければならなくなります。

00:01:01.640 --> 00:01:06.560 align:middle
さらに、メソッドの場合分けを
追加することは厄介で

00:01:06.840 --> 00:01:10.440 align:middle
瑣末なことに
追い立てられてしまいます。

00:01:10.720 --> 00:01:13.760 align:middle
動物を追加すると
このメソッドが長大になって

00:01:13.920 --> 00:01:17.160 align:middle
それぞれの動物の種類も
細くなっていくでしょう。

00:01:17.320 --> 00:01:21.760 align:middle
例えば犬に尻尾があるというような
単純な特徴であっても

00:01:21.920 --> 00:01:25.920 align:middle
それぞれに場合分けを
作らなければならなくなります。

00:01:26.120 --> 00:01:31.640 align:middle
コードがどんどん煩雑になり
読みにくくなっていきます。

00:01:32.240 --> 00:01:35.760 align:middle
だから、そんなことはやめて
メッセージを送ります。

00:01:36.080 --> 00:01:38.480 align:middle
何度も繰り返してきたポイントです。

00:01:38.640 --> 00:01:42.240 align:middle
覚えるべきキーポイントは
メッセージを送ることです。

00:01:42.880 --> 00:01:46.280 align:middle
先ほどのコードは
このように置き換わります。

00:01:47.040 --> 00:01:51.160 align:middle
それぞれの関係するクラスに
showHappiness メソッドがあり

00:01:51.320 --> 00:01:56.480 align:middle
各クラスがそれぞれの動物が
どう喜びを示すのかを決めます。

00:01:56.760 --> 00:02:02.720 align:middle
どんな動物であれ、やることは
メッセージを送ることだけです。

00:02:05.560 --> 00:02:07.560 align:middle
動物に showHappiness を送ります。

00:02:08.600 --> 00:02:11.360 align:middle
そして 1 つのメソッドが
実行されます。

00:02:11.520 --> 00:02:15.040 align:middle
Pharo は if という機能を
追い出そうとしているということです。

00:02:15.200 --> 00:02:19.960 align:middle
動物の種類に応じてどのメソッドを
適用するのか Pharo が決めます。

00:02:20.120 --> 00:02:22.920 align:middle
これが自動的に実行されます。

00:02:23.120 --> 00:02:27.480 align:middle
オブジェクトの種類ごとに
if を指定する必要はありません。

00:02:28.040 --> 00:02:31.200 align:middle
そんなことをするとコードの
統一性とダイナミズムが減ります。

00:02:32.560 --> 00:02:36.040 align:middle
では、その特殊なケースである
nil について議論します。

00:02:36.440 --> 00:02:39.160 align:middle
あるメソッドが nil を返すと

00:02:39.320 --> 00:02:43.120 align:middle
クライアントは if を
使わざるを得なくなります。

00:02:43.280 --> 00:02:46.200 align:middle
if は褒められたものではない
のに反して。

00:02:47.520 --> 00:02:50.520 align:middle
パラメータと Interencer を使った

00:02:50.760 --> 00:02:55.440 align:middle
例題コードがあります。

00:02:55.600 --> 00:02:57.880 align:middle
コードの種類は重要ではありません。

00:02:58.160 --> 00:03:01.440 align:middle
ここを見ればわかるように
場合によって nil が返されます。

00:03:01.840 --> 00:03:04.480 align:middle
つまり、このコードを使う時は

00:03:04.760 --> 00:03:08.600 align:middle
メッセージの返り値を
チェックする必要があります。

00:03:08.800 --> 00:03:11.480 align:middle
rulesForFact: が
nil を返したかどうかを。

00:03:11.680 --> 00:03:14.560 align:middle
応答によって異なることをします。

00:03:14.720 --> 00:03:17.280 align:middle
この場合には

00:03:17.880 --> 00:03:20.280 align:middle
複数形を使っているので

00:03:20.440 --> 00:03:23.960 align:middle
このメソッドはおそらく
コレクションを返すのでしょう。

00:03:24.200 --> 00:03:26.880 align:middle
nil を避ける効果的な解決策は

00:03:27.080 --> 00:03:31.000 align:middle
この場合は空のコレクションを
返すことです。

00:03:31.200 --> 00:03:33.080 align:middle
これで大丈夫な場合が多くあります。

00:03:33.400 --> 00:03:38.520 align:middle
nil を返さずに空のコレクションを返すことで
コードがシンプルになります。

00:03:38.880 --> 00:03:42.400 align:middle
クライアントは単にそのコレクションを
列挙するだけだからです。

00:03:42.560 --> 00:03:45.360 align:middle
もし空だったら何もしません。

00:03:46.480 --> 00:03:48.400 align:middle
例外を使うケースもあります。

00:03:48.840 --> 00:03:52.360 align:middle
ファイルストリームがあって

00:03:52.520 --> 00:03:56.320 align:middle
書き込みモードで open しておらず
エラーにする場合には

00:03:56.560 --> 00:04:01.640 align:middle
nil を返すかわりに
例外をあげてシステムに知らせます。

00:04:01.920 --> 00:04:05.600 align:middle
Pharo ではこれを
「例外を申し立てる」と呼びます。

00:04:05.760 --> 00:04:09.560 align:middle
Exception クラスかそのサブクラスの
インスタンスを生成して

00:04:09.720 --> 00:04:11.960 align:middle
signal メッセージを送ります。

00:04:13.680 --> 00:04:19.640 align:middle
こうすることで、問題がありそうな時に
nextPutAll: メソッドのクライアントに

00:04:19.800 --> 00:04:23.960 align:middle
返り値が nil かどうかを
チェックせずに済みます。

00:04:24.200 --> 00:04:26.800 align:middle
クライアント側や
クライアントのクライアントなどが

00:04:26.960 --> 00:04:31.680 align:middle
その例外を処理します。

00:04:31.880 --> 00:04:37.840 align:middle
特定のレベルで集中して
例外を捕まえることができます。

00:04:38.560 --> 00:04:40.240 align:middle
これで if の使いすぎを避けられます。

00:04:40.880 --> 00:04:45.720 align:middle
他にも、インスタンス変数の値が
初期化されているかどうかを

00:04:45.880 --> 00:04:49.280 align:middle
確認するための nil チェックも
見かけます。

00:04:49.600 --> 00:04:54.800 align:middle
変数がまだ nil であれば
何らかの反応をするようなコードは

00:04:54.960 --> 00:04:59.200 align:middle
すぐに初期化して

00:04:59.360 --> 00:05:01.960 align:middle
あらゆる場合に対応できる値に
したほうが良いです。

00:05:02.120 --> 00:05:03.120 align:middle
つまりここでは

00:05:03.600 --> 00:05:06.680 align:middle
members は
コレクションを格納しますが

00:05:06.840 --> 00:05:10.600 align:middle
nil ではなく空のコレクションで
初期化します。

00:05:10.920 --> 00:05:13.520 align:middle
これもまた
うまくいく場合が多くあります。

00:05:13.960 --> 00:05:18.000 align:middle
変数に初期値を与えたいけれども

00:05:18.400 --> 00:05:22.680 align:middle
その初期値を計算するのに
大きなコストがかかるようならば

00:05:22.840 --> 00:05:26.560 align:middle
初期値を計算するのをギリギリまで
遅らせることができます。

00:05:26.720 --> 00:05:30.520 align:middle
計算しなくて済む場合もあるので
実行時間の節約になります。

00:05:31.320 --> 00:05:35.040 align:middle
そんな場合には
遅延初期化を使います。

00:05:35.200 --> 00:05:38.280 align:middle
値が必要とされた時に初期化をします。

00:05:38.680 --> 00:05:42.400 align:middle
もし値がまだ nil であれば
値を代入します。

00:05:42.560 --> 00:05:47.240 align:middle
もし値がもう nil でなければ
その値をそのまま返します。

00:05:48.000 --> 00:05:52.600 align:middle
ここに nil と if がありますが
1 つしかありません。

00:05:53.160 --> 00:05:57.920 align:middle
この変数を使う人は
この decent メソッドを使うことで

00:05:58.520 --> 00:06:00.720 align:middle
nil かどうかチェックする
必要がありません。

00:06:01.320 --> 00:06:03.960 align:middle
時々あるのですが

00:06:04.520 --> 00:06:09.840 align:middle
反応する必要があるかどうか
チェックする必要があります。

00:06:10.320 --> 00:06:12.160 align:middle
この例題のような場合です。

00:06:12.800 --> 00:06:15.840 align:middle
ここに ToolPalette があります。

00:06:16.120 --> 00:06:19.440 align:middle
もしツールが選択されていたら
反応します。

00:06:19.600 --> 00:06:22.960 align:middle
もし選択されていなければ
反応しないでおきます。

00:06:23.640 --> 00:06:26.480 align:middle
もし selectedTool が
nil を返したら

00:06:26.720 --> 00:06:31.600 align:middle
ツールが選択されていないので
何もする必要がありません。

98 align:middle
00:06:31,800 --> 00:06:35,760
selectedTool が何かを返したら

00:06:36.000 --> 00:06:40.080 align:middle
それに対して何かするように
頼みます。

00:06:41.040 --> 00:06:42.920 align:middle
これの代わりになる良い方法は

00:06:43.360 --> 00:06:45.720 align:middle
NullObject パターンを使うことです。

00:06:45.880 --> 00:06:50.400 align:middle
ツールのあるなしで
2 つの場合に分けるのではなく

00:06:50.600 --> 00:06:54.440 align:middle
ツールの 1 つは何もしないツールにして
1 つの場合にします。

00:06:54.600 --> 00:06:57.120 align:middle
このツールは
デフォルトで選択されています。

00:06:57.360 --> 00:07:01.840 align:middle
アクションの依頼に対して
何もしないツールを作るのです。

00:07:03.120 --> 00:07:09.000 align:middle
ツールを選ばないのではなく
何もしないツールを選ぶのです。

00:07:10.360 --> 00:07:14.800 align:middle
NullObject についてもっと知りたければ
これらの文献を読んでください。

00:07:15.680 --> 00:07:16.840 align:middle
まとめます。

00:07:17.000 --> 00:07:19.640 align:middle
メッセージは if よりも有効です。

00:07:19.840 --> 00:07:22.520 align:middle
if を使う場合もあるでしょうが

00:07:22.680 --> 00:07:27.680 align:middle
if を避けて代わりにメッセージを送る
ことができる場合も多くあります。

00:07:28.840 --> 00:07:34.160 align:middle
nil を返すのは避けましょう。
返り値が nil かチェックするための

00:07:34.360 --> 00:07:38.280 align:middle
if を入れなければならなくなります。

00:07:39.440 --> 00:07:44.720 align:middle
初期化は生成時に行うか
あるいは遅延初期化を使いましょう。

00:07:45.680 --> 00:07:50.760 align:middle
デフォルトまたは何もしない振る舞いを
表すオブジェクトを作りましょう。

00:07:50.960 --> 00:07:54.960 align:middle
これは Pharo だけでなく
あらゆるオブジェクト指向言語で有効です。

00:07:55.200 --> 00:08:00.840 align:middle
どんな言語を使うにせよ、これらの
ポイントを覚えておくことが大事です。

