WEBVTT

00:00:00.720 --> 00:00:05.880 align:middle
こんにちは
このビデオでは Pharo の重要な機能である

00:00:06.080 --> 00:00:07.920 align:middle
doesNotUnderstand: フックを説明します。

00:00:08.080 --> 00:00:13.400 align:middle
もうデバッガーウィンドウで
このメッセージを見ましたよね。

00:00:13.920 --> 00:00:16.840 align:middle
それはどこから来て
何をするものでしょう？

00:00:17.280 --> 00:00:20.080 align:middle
例を見てみましょう。

00:00:20.400 --> 00:00:22.280 align:middle
オブジェクト node1 があります。

00:00:22.640 --> 00:00:27.520 align:middle
このオブジェクトに coucou: stef
メッセージを送ってみます。

00:00:28.280 --> 00:00:31.280 align:middle
node1 から Object クラスまで

00:00:31.840 --> 00:00:33.920 align:middle
メソッド探索していきます。

00:00:34.200 --> 00:00:37.720 align:middle
coucou: メソッドは
このクラスでは見つかりません。

00:00:37.920 --> 00:00:42.320 align:middle
そこでスーパークラスへ行きます。
しかし、ここにもありません。

00:00:42.720 --> 00:00:45.520 align:middle
仮想的に探索しても見つからないので

00:00:45.800 --> 00:00:51.040 align:middle
そのメッセージを具体化します。
具体化（レイフィケーション）については

00:00:51.200 --> 00:00:56.440 align:middle
イントロスペクションとリフレクション
のビデオで議論しました。

00:00:56.920 --> 00:01:02.640 align:middle
具体化とは、暗黙的な概念を
オブジェクトとして表現することです。

00:01:02.920 --> 00:01:04.520 align:middle
ここにメッセージがあります。

00:01:04.920 --> 00:01:07.920 align:middle
このメッセージを表現する
オブジェクトを生成します。

00:01:08.080 --> 00:01:10.400 align:middle
Messageクラスのインスタンスです。

00:01:10.680 --> 00:01:15.000 align:middle
仮想システムはオブジェクト node1 に

00:01:15.200 --> 00:01:17.320 align:middle
メッセージを再送します。

00:01:17.760 --> 00:01:22.800 align:middle
doesNotUnderstand: メッセージを
さきほどのオブジェクトを引数として送ります。

00:01:22.920 --> 00:01:27.000 align:middle
これでメッセージ探索を新たに実行します。

00:01:27.200 --> 00:01:32.440 align:middle
doesNotUnderstand: メソッドは
Node クラスでは見つかりません。

00:01:32.720 --> 00:01:37.640 align:middle
そこでスーパークラスを辿って探します。

00:01:37.840 --> 00:01:40.920 align:middle
DNU（doesNotUnderstand:）メソッド
が見つかります。

00:01:41.160 --> 00:01:44.440 align:middle
これでそのメソッドを実行できます。

00:01:47.080 --> 00:01:49.920 align:middle
doesNotUnderstand: は

00:01:50.200 --> 00:01:53.840 align:middle
メッセージが失敗した時に

00:01:54.280 --> 00:01:56.280 align:middle
システムがあなたに送るメッセージです。

30 align:middle
00:01:57,080 --> 00:02:00,680
どんなクラスでもこのメソッドを再定義して

00:02:01.280 --> 00:02:06.800 align:middle
メッセージを理解できなかった時の
特殊な振る舞いを定義できます。

00:02:07.320 --> 00:02:09.840 align:middle
このメソッドを使って色々な機能を
構築することができる

00:02:10.320 --> 00:02:13.800 align:middle
とても重要な道具です。

00:02:14.080 --> 00:02:17.440 align:middle
自動的な移譲（デリゲーション）や

00:02:17.720 --> 00:02:20.520 align:middle
分散プログラミングなどに有用です。

00:02:21.400 --> 00:02:25.080 align:middle
ここで doesNotUnderstand: の
利用例をいくつか見てみましょう。

00:02:25.720 --> 00:02:30.400 align:middle
受け取った全てのメッセージを
何か別のオブジェクトに転送したいとします。

00:02:31.640 --> 00:02:37.200 align:middle
単純な移譲としては
メッセージを転送する対象を

00:02:37.400 --> 00:02:39.320 align:middle
格納するオブジェクトを作ります。

00:02:39.520 --> 00:02:42.200 align:middle
doesNotUnderstand: メソッドを
再定義します。

00:02:42.400 --> 00:02:45.560 align:middle
引数として aMessage オブジェクト
が渡されて

00:02:45.760 --> 00:02:49.280 align:middle
その中に失敗したメッセージの
セレクターが格納されています。

00:02:49.680 --> 00:02:53.400 align:middle
そこでこのメッセージに
再送するようお願いします。

00:02:53.760 --> 00:02:59.920 align:middle
sendTo: self target とすると

00:03:00.520 --> 00:03:03.320 align:middle
別のオブジェクトにそのメッセージが
再送されます。

00:03:04.320 --> 00:03:07.400 align:middle
コードの可読性を壊してしまうような

00:03:07.920 --> 00:03:12.400 align:middle
強力な機能なので、注意してください。

00:03:12.760 --> 00:03:15.160 align:middle
ここに説明している通りです。

00:03:16.000 --> 00:03:20.360 align:middle
このメッセージが最終的に誰が受け取るか
このコードに書いてあります。

00:03:20.920 --> 00:03:23.680 align:middle
ツールや高度な仕組みを実現する上で

00:03:24.080 --> 00:03:28.080 align:middle
とても有用な機能です。

00:03:29.720 --> 00:03:33.720 align:middle
もう 1 つの例として
ログ取りプロキシを見てみましょう。

00:03:33.920 --> 00:03:36.320 align:middle
どんなものかというと

00:03:36.560 --> 00:03:40.400 align:middle
メソッドを極少数しか持たない
小さなオブジェクトを作って

00:03:40.600 --> 00:03:44.360 align:middle
doesNotUnderstand: メソッドを
変更します。

00:03:44.800 --> 00:03:48.840 align:middle
そしてドメインオブジェクトの代わりに

00:03:49.400 --> 00:03:53.920 align:middle
このプロキシオブジェクトを
become: で忍び込ませます。

00:03:54.840 --> 00:03:58.840 align:middle
まず、プロキシオブジェクトを作ります。

00:03:59.360 --> 00:04:02.840 align:middle
プロキシオブジェクトに
元オブジェクトを与えます。

00:04:03.080 --> 00:04:06.560 align:middle
元オブジェクトというのは
このプロキシで置き換える

00:04:07.400 --> 00:04:08.560 align:middle
対象のオブジェクトです。

00:04:08.840 --> 00:04:14.720 align:middle
invocationCount をインクリメントして
メッセージを数えます。

00:04:15.400 --> 00:04:20.760 align:middle
まだメッセージを受け取っていないので
カウンタを 0 に初期化します。

00:04:20.920 --> 00:04:25.400 align:middle
そして元オブジェクトを与えます。
この self は 後で入れ替わります。

00:04:26.520 --> 00:04:29.760 align:middle
ここでこのプロキシの
DNU メソッドを再定義します。

00:04:29.920 --> 00:04:33.360 align:middle
理解できないメッセージを
受け取るたびに

00:04:33.560 --> 00:04:38.840 align:middle
それがトランスクリプトに表示され
カウンタをインクリメントしていきます。

00:04:39.200 --> 00:04:43.400 align:middle
そしてそのメッセージを
元オブジェクトに転送します。

00:04:44.080 --> 00:04:47.600 align:middle
前の例と同様
メッセージを別のオブジェクトに再送します。

00:04:48.800 --> 00:04:52.920 align:middle
Messageクラスが実装している
sendTo: の代わりに、見ての通り単に

00:04:53.080 --> 00:04:57.400 align:middle
perform:withArguments:　メソッドを
使います。

00:04:57.640 --> 00:05:01.440 align:middle
もうこれについては前の講義で
説明しました。

00:05:02.920 --> 00:05:05.160 align:middle
例を見てみましょう。

00:05:06.200 --> 00:05:09.520 align:middle
このログ取りプロキシの使い方は

00:05:10.000 --> 00:05:13.280 align:middle
まず point オブジェクトを生成して

00:05:14.040 --> 00:05:16.680 align:middle
それから become: して

00:05:17.040 --> 00:05:20.200 align:middle
この point オブジェクトを指している
すべてのものを

00:05:20.680 --> 00:05:24.280 align:middle
ログ取りプロキシを生成して

00:05:25.520 --> 00:05:27.320 align:middle
それにすり替えます。

00:05:27.760 --> 00:05:30.760 align:middle
point オブジェクトにメッセージを送ると

00:05:30.920 --> 00:05:36.600 align:middle
become: したので実際には
ログ取りプロキシになっていて

00:05:36.840 --> 00:05:39.200 align:middle
メッセージを送るたびに

00:05:39.840 --> 00:05:42.000 align:middle
トランスクリプトに表示して

00:05:42.720 --> 00:05:45.320 align:middle
カウンタがインクリメントされます。

00:05:46.000 --> 00:05:48.800 align:middle
doesNotUnderstand: に書いた通りです。

00:05:49.040 --> 00:05:53.200 align:middle
最後にカウンタは 3 になります。

00:05:54.440 --> 00:05:57.840 align:middle
最後の例で見た通り
このプロキシフレームワークには

00:05:58.000 --> 00:06:00.200 align:middle
制限があります。

00:06:00.520 --> 00:06:06.440 align:middle
例えば、そのオブジェクトが self に
送るメッセージを捕まえることはできません。

00:06:06.640 --> 00:06:07.840 align:middle
これはちょっとトリッキーです。

00:06:08.040 --> 00:06:14.160 align:middle
クラスには become: は使えません。
リフレクションには制限があります。

00:06:14.720 --> 00:06:18.720 align:middle
プロキシと元オブジェクトが
同じメッセージを受け付ける場合にも

00:06:18.920 --> 00:06:21.400 align:middle
リスクがあります。

00:06:21.760 --> 00:06:24.600 align:middle
プロキシにメッセージを送った時に

00:06:24.840 --> 00:06:28.360 align:middle
そのまま応答してしまい
DNU で捕まえて元オブジェクトに

00:06:28.560 --> 00:06:31.520 align:middle
転送することができません。

00:06:32.280 --> 00:06:37.000 align:middle
Pharo には全てトラップすることができる
プロキシフレームワークが別にあります。

00:06:37.160 --> 00:06:42.200 align:middle
しかし、そういったものは
この簡単な実装例よりも複雑です。

00:06:42.800 --> 00:06:46.760 align:middle
この技術の他の応用例としては

00:06:47.080 --> 00:06:53.280 align:middle
アクセサやメソッドを動的に生成する
というものがあります。

00:06:53.840 --> 00:06:58.400 align:middle
ここに、再定義した
doesNotUnderstand: メソッドがあります。

00:06:58.800 --> 00:07:01.200 align:middle
メッセージを受け付けると

00:07:01.400 --> 00:07:06.200 align:middle
対応するインスタンス変数がないか確認して

00:07:06.400 --> 00:07:11.200 align:middle
もしあれば、新しいメソッドを生成して
compile: を使って

00:07:11.560 --> 00:07:14.040 align:middle
そのクラスの新しいメソッドとします。

00:07:16.360 --> 00:07:19.600 align:middle
これは変数の値を返します。

00:07:19.760 --> 00:07:23.600 align:middle
ここで変数の
リードアクセサを生成しています。

00:07:24.080 --> 00:07:28.560 align:middle
もしメッセージにマッチする

00:07:28.920 --> 00:07:32.840 align:middle
インスタンス変数がない場合には
super doesNotUnderstand: を送ります。

00:07:33.400 --> 00:07:38.400 align:middle
これを使って
実際に呼ばれたかどうかに従って

00:07:38.920 --> 00:07:41.840 align:middle
自動的にリードアクセサを定義できます。

00:07:42.760 --> 00:07:45.280 align:middle
まとめると

00:07:45.400 --> 00:07:47.920 align:middle
小さなオブジェクトの使い方を
見てきました。

00:07:48.080 --> 00:07:51.640 align:middle
Object クラスのインスタンスではなく

00:07:51.840 --> 00:07:54.040 align:middle
protoObject クラスのインスタンスです。

00:07:54.200 --> 00:07:56.920 align:middle
プロキシの基盤として使うことができます。

00:07:57.200 --> 00:08:01.400 align:middle
doesNotUnderstand: を再定義することで

00:08:01.920 --> 00:08:07.800 align:middle
メッセージの失敗を捕捉して
再送することができます。

00:08:08.320 --> 00:08:13.840 align:middle
この強力なフックは
Pharo の多くのツールの基盤になっています。

00:08:14.560 --> 00:08:18.000 align:middle
しかし、非常に注意深く使ってください。

00:08:18.280 --> 00:08:21.760 align:middle
本当に必要な時だけ使ってください。

00:08:22.080 --> 00:08:27.320 align:middle
ドメインコードには使わないように。
とても高度な技術です。

