こんにちは。今日はプログラムの
とても微妙なところを 分析してみましょう。
まず最初に、ダイスプログラムを 振り返ってみましょう。
覚えていると思いますが この演習ではダイスを定義して
色々な面の数をもつダイスの インスタンスを定義しました。
ダイスハンドルというクラスを 定義しました。
そして DiceHandle クラスに
+ メソッドを実装して ダイスハンドル同士を足し合わせて
新しいダイスハンドルを 作れるようにしました。
これがこのクラスのコードです。
DiceHandle new があります。
新しいダイスハンドルを 作って
レシーバーのダイスと
もう1方のダイスを加えて
メソッドの最後でこのハンドルを 返します。いいですね？
今回は、この + メソッドで
DiceHandle new と書く場合と self class new と書く場合の
違いを見ていきます。 そしてこれらのうち
どちらが優れているか その理由がわかるでしょう。
ここにそのプログラムがあります。
もし DiceHandle のサブクラスとして MemoDiceHandle を作って
DiceHandle クラスから継承した + メソッドで MemoDiceHandle 同士を
足し合わせたい場合には
結果は DiceHandle クラスの インスタンスになります。
MemoDiceHandle クラスの インスタンスではありません。
これは問題です。 足し合わせたら
同じ種類のものを 返してほしいからです。
どうしたら良いでしょう？
1 つ目の解決策は
DiceHandle クラスの
+ メソッドの実装を変えます。
+ メソッドです。いいですね？
そしてこのメソッドを追加します。 self handleClass
インスタンス変数ではなく
handleClass というメソッドを 使います。 that I call handleClass.
DiceHandle では DiceHandle クラスを返します。
サブクラスのMemoDiceHandle クラスでは MemoDiceHandle クラスを返します。
つまり、単純に handleClass メソッドを 再定義することで
正しいクラスのインスタンスを 得ることができます。
同じコードを MemoDicehandle で実行したら、
MemoDiceHandle クラスの インスタンスが得られます。
MemoDiceHandle クラスの handleClass メソッドを
再定義したからです。 サブクラスのインスタンスが得られます。
これで目的は達成できます。
問題は
DiceHandle のサブクラスを 定義するたびに
handleClass メソッドを 再定義しなければならないことです。
再定義しなければ、 + メソッドは 正しいクラスのインスタンスを返しません。
めんどくさいですね。 常に再定義しなければなりません。
もう少し良い方法があります。
2 つ目の解決策は
DiceHandle クラスの + メソッドで
self class new. とします。
レシーバーにクラスを尋ねて
インスタンスを得ます。
self class は常にレシーバーの クラスを答えるので
もしレシーバーがサブクラスならば
正しくサブクラスを答えます。 例えば、MemoDiceHandle クラスです。
レシーバーと同じ種類の インスタンスが得られます。
まとめると
見ての通り
ダイスハンドルに + メッセージを送ると
クラス名を書いた場合には
サブクラスのインスタンスを得る上で 邪魔になります。
self class new とすることで レシーバーのインスタンスが得られます。
サブクラスの場合も含めて。
つまり、self class new とした方が ずっと良いです。
レシーバーの種類に応じて
そのクラスのインスタンスを 直接得ることができます。