こんにちは。 前回のセッションでは
真偽値の not と or の 実装方法をみてきました。
3つ目の問題が残っています。 一体なぜこれらの問題をやるのか？
それを学びます。
実装を振り返ってみましょう。 not について。2つのオブジェクトがありました。
true と false です。
True クラスと False クラスのインスタンスでした。
not メッセージを送ると
それぞれに対応するクラスに問い合わせて メソッドを実行しました。
問題ないですね。
伝えたことは
何かと言うと
まず第一に、レシーバーに決めさせること。
つまり、自分では何も決めないで
メッセージを送ることで解決します。
経験則が2つありました。 レシーバーに決めさせること。
そして、「求めるな、命じよ」です。
これについては、後でまた出てきます。
では、練習問題自体を見てみましょう。
さて、これは何なのでしょう？
あなたが今後人生において 真偽値を実装することは決してないでしょう。
少なくとも、私はそう願います。
では全く使い道がないことでしょうか？
背後にある教えは、何でしょうか？
私はこの問題を問うことは とても重要なことだと考えています。
実装はあんな感じだとして だからどうだというのでしょう？
メッセージ送信をする時にはいつも
case 文を実行しているということです。
C プログラミング等によくあることです。
メッセージを送ることは 複数の選択肢から選ぶということです。
興味深いことは メッセージを送ると
単なる case 文ではないということです。 動的な case 文になっています。
実際、メッセージ送信はロードされている クラスや生成されたインスタンスに依存します。
Java でプログラムを書く時にはよく
x.f() を書くことで
メソッド f を実行します。
ここで説明していることは、つまり このピリオド（.）は
選択をおこなう演算子だということです。
とても大事なことは
この選択は動的だということです。
これまであまり言ってきませんでしたが
これこそが、例をもって示したかったことなのです。
まとめると メッセージを送ることは
動的な case 文のような機能を果たします。
動的というのは ロードされているクラスに依存するという意味です。
この真偽値の例題では 2つのインスタンスと2つのクラスを扱いました。
たとえ50個だったとしても 同じように動きます。
バーチャルマシンにメッセージを送ることで
（Pharo は Java や C# のように バーチャルマシンを使います）
バーチャルマシンの実行装置が
レシーバーのクラスに応じて 正しいメソッドを選択します。
したがって、メッセージ送信は 選択演算子なのです。
条件分岐を使うたびに
それを
バーチャルマシンによる選択に 置き換えることができます。
つまり、not についての解答は
プログラムを実装する時には
バーチャルマシンによる選択を 使うべきだということです。
if 文を使う必要はありません。
なぜなら、メッセージを送ることが if や条件分岐と同じ意味になるのです。
ここで疑問に思うかもしれません。
最初の練習問題を全く別の方法で実装していたら どうなのだろうか？と。
もし練習問題が「Boolean クラスに
not や or を実装しなさい」だったら どうでしょう？
今回の解答のやり方では うまくいかないでしょう。
おかしいですね。 どういうことでしょうか？
クラスが1つあるか複数あるかは アプリケーションの設計に
とても大きな影響を与えます。
まったくもって
クラスは分岐や選択の役割を 担っているのです。
ヨーグルトを選ぼうとしているとして
店にヨーグルトのポットが1つしかなければ そのヨーグルトを選ぶしかないのです。
そういうことなのです。
つまり、クラスは
継承木の中での1つの case を表しています。
それが意味することは
1つの大きく太ったクラスに メソッドが沢山あるような
そんなデザインがあれば
それと同じことを階層を使って表現できる ということです。
そのほうが良い設計です。 よりモジュール化されています。
必要ならば別の選択肢を加えることも 簡単にできます。
「これは悪くないが
新しい選択肢を持てるように改良できるね」 と言って拡張するのです。
さらに複雑度を減らすことができます。
1つのクラスに集中することができます。 あまりにも多くの条件を抱えたものではなく。
片方の手には選択演算子があり
もう一方の手には選択肢を表したものを持っています。
それらをくっつけると 良い品質の OOP になります。
さらに良いことに
階層による解決を使うと
それをパッケージ化することができます。
つまり、ある部分はコアとしてパッケージして 別の部分をプラグインとしてパッケージできます。
そして顧客に言うのです。 「この機能が必要であれば
この有償プラグインをダウンロードしてください」
そしてそのコードを動的にロードします。
このクラスのインスタンスを生成すると
オペレーションメッセージを送れば
プラグインのコードがシステムの中で 実行されます。
それが OOP のエッセンスです。
メッセージを送ると 正しいメソッドが選択される
そしてシステムが正しいメソッドを 選択することを知っていることで
よりエレガントな実装をすることができます。
何を学んだのでしょうか？
学んだことは、メッセージを送ることで レシーバーに選択させて何かを決めさせることです。
クライアントは何も決める必要ありません。
クライアントコードは宣言的です。
条件分岐はありません。命令を与えるのです。 「これをやれ」「あれをやれ」「開け」「閉じろ」と。
「このクラスに属していますか？」や 「閉じられていますか？」ではなく。
違いはレシーバーが動的に置き換えられる 可能性があることです。
このことは後でまた出てきます。 ただし直接ではありません。暗黙に。
そういうことで、多くの場合 if 文を書くことを避けるようにしてください。
できるだけオブジェクトとメッセージを使うように。
いつもそうだというわけではないですが 少なくともできるだけ使うようにしてください。
実行エンジン バーチャルマシンは
メッセージを送るたびに 条件スイッチとして動作します。
それを使うことです。
キーボードを打つ時はいつも アンチ if キャンペーンを楽しんでください。
if 文を書くのをやめさせるために プログラマー達がこのキャンペーンを立ち上げました。
さて、このセッションでは何を学んだでしょうか？
2つのことがありました。 Java や Pharo で
x.f() と書いたら
選択肢を作ることになります。
レシーバーに応じて実行されるべき メソッド f が選択されます。
つまり選択演算子ということです。
そして階層が可能な選択肢を表現します。
つまりどんな選択が可能かを決める 枠組みだということです。
結果として条件分岐のない 拡張性のあるプログラムを書くことができます。
これで Pharo でのオブジェクト設計についての
最初のセッションを終わります。
次のセッションでもオブジェクト設計について さらに見ていきます。