if と別れる50の方法《04》ジャンケン問題, double-dispatch:山羊さん郵便に学ぶ
Python.use(better) # OOP への道 《Python3.1, Jython2.5.0, IronPython2.6.x》
ジャンケン問題, double-dispatch
■ 概要
if/switch 文は多くの問題を抱え、OOP を実践するときの「障害」になります。
伝統的なC言語風の for 文や悪名高い switch 文、配列の呪縛から解かれ、オブジェクト指向プログラミング〔OOP〕の醍醐味を堪能するための準備を行います。
■ 関連記事
- Java プログラマーのための Python 導入ガイド《Jython2.5》改訂版
- 例題で学ぶ Jython/Swing デザインパターン《Jython2.5》改訂版
- ゲームに学ぶ Jython/Swing フレームワーク《Jython2.5》改訂版
- IronPython で学ぶ WPF プログラミングの世界《IronPython2.6》改訂版
ジャンケン問題とは
《承前》
OOP による解法:山羊さん郵便に学ぶ
前述(思考回路を switch) したように、オブジェクト指向の原則は「オブジェクトにメッセージを送る」こと(メッセージ送受信)です。 そこで、この原則に沿って、ジャンケン問題を解決します。
■ メッセージ送受信:♪山羊さんゆうびん
「オブジェクトにメッセージを送る」様子を電子メールに例えました。それには、送信者 from: と受信者 to: を決める必要があります。ここでは、2人(AさんとBさん)の間で、メールを送受信します。つまり、電子メールでジャンケンをするのです。
さらに、お互いの手の内を曝さずに、その勝敗を決します。自分は「グー/チョキ/パー」の3つの手の中からひとつを選びます。相手も同じです。では、メールで勝敗を決するには、どのような内容を送受信すれば良いのでしょうか。
■ メッセージの送信:♪白山羊さんからお手紙…
メッセージを利用する利点は、その状況が「実行時」に確定することです。
メッセージを送信するときに、自分(B)の状態は確定します。まだこの状態では、相手(A)の状態は確定していません。3つの可能性があるだけです。この状況をコードで表現すると、次のようになります。
p1 = Player("A") p2 = Player("B") p1.hand.judge(p2.hand) # あなた(の手)は私(の手)に勝てますか
このとき、.hand には、R(rock)/P(paper)/S(scissors) の3つの選択肢(可能性)があります。それは、p1,p2 が手を差し出したとき(実行時)に確定します。このように、メッセージは「実行時まで確定しない状況」を記述するのに適しています。実行時に確定する状況には、次のようなものが考えられます。
- メッセージを受信(送信)したときに、p1.hand が確定します。
- メッセージを受信(返信)したときに、p2.hand が確定します。
■ メッセージの受信:♪黒山羊さんったら…
メッセージを受信したときに、受信者(A)の状態が確定します。つまり、可能性はただ1つです。なぜなら、同時に複数の状態は取れないからです。このとき、送信者(B)の状態を知る必要はありません。
《Note》もちろん送信者の状態を知ることは可能です。すると、3つの可能性を考慮する必要があり、switch の呪縛からは逃れられません。黒山羊さんは、手紙を読まずに食べてしまいました。手紙には「私の手は○○です」と書かれていたかもしれません。しかし、白山羊さんの手を知ら(手紙を読ま)なくても、勝敗は判定できます。
■ メッセージの返信:♪仕方がないからお手紙…
送信者の状態が分からなくても、それが誰かは分かります。そのとき、返信すべき相手(B)が確定します。メッセージを受信するまでは、誰に返信すべきか分かりません。すると、受信者にできることはただ1つです。送信者が誰であろうと、同じ内容を返信するだけです。
返信すべき内容はひとつだけです。受信者がグーなら、その内容は「あなたはグー(私)に勝てますか」になります。チョキ/パーの場合も同様です。すると、送信者の状態に依存しないで、確定した送信者に勝敗の判定を委ねられます。ここで注目して欲しいのは、他の場合(チョキ/パー)を考える必要がなく、相手の状態も知る必要がないことです。
メッセージを受信したときの自分の手が「グー」だとします。すると、返信すべき内容は次のようになります。
メッセージを送信(返信)するときに、自分(A)の状態は確定します。まだこの状態では、相手(B)の状態は確定していません。3つの可能性があるだけです。この状況をコードで表現すると、次のようになります。
class PlayerR: # Rock ... def judge(self, player): player.judgeFromPlayerR(self) # あなた(の手)は私(グー)に勝てますか
このとき「グー」のことだけを考えればよく、「チョキ」や「パー」のことを考える必要はありません。クラス PlayerP, PlayerS についても同様です。それぞれが「チョキ」や「パー」のことだけを考えます。
■ メッセージの受信:♪さっきの手紙の…
メッセージを受信したときに、受信者(A)の状態が確定します。つまり、可能性はただ1つです。なぜなら、同時に複数の状態は取れないからです。このとき、送信者の状態を知るのに、手紙を読む必要はありません。なぜなら、subject: に「あなたはグーに勝てますか」とあるメッセージの送信者は、グーさん以外に考えられないからです。すると、その勝敗は明らかです。
class PlayerP: # Paper ... def judgeFromPlayerR(self, player): return self # 私(の手)の勝ちですね
《Note》こうして、一度も手紙の内容を読まずに、勝敗は決しました。お腹を減らした白山羊さんが、手紙を読まずに食べてもかまいません。だったら、最初から黒山羊さん宛に手紙など書かずに、それを食べてしまえば良かったのですが…。(^.^)
Tips
》作業中です《