if と別れる50の方法《04》ジャンケン問題, double-dispatch:山羊さん郵便に学ぶ

記事一覧if 篇for 篇配列 篇

Python.use(better) # OOP への道 《Python3.1, Jython2.5.0, IronPython2.6.x》
ジャンケン問題, double-dispatch

《著》真樹育未・後藤いるか・小粒ちゃん《監修》小泉ひよ子とタマゴ倶楽部
第0版♪1988/10/12 ● 第1版♪1993/05/23 ● 第2版♪2003/05/25

■ 概要

if/switch 文は多くの問題を抱え、OOP を実践するときの「障害」になります。

伝統的なC言語風の for 文や悪名高い switch 文、配列の呪縛から解かれ、オブジェクト指向プログラミング〔OOP〕の醍醐味を堪能するための準備を行います。

ジャンケン問題とは

承前

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

》作業中です《

Last updated♪2009/07/18