自分がOOPをそれっぽく学んだのは、サンディ・メッツの「オブジェクト指向設計実践ガイド」だが、この本だとダック・タイピングはバキバキにでてくる一方であまりポリモーフィズムについては詳しく書かれていない。thoughtbotのブログの記事、Rubyとポリモーフィズムによると、Rubyにおけるポリモーフィズムは「継承」と「ダック・タイピング」によって実装できるらしい。
オブジェクト指向設計実践ガイド ~Rubyでわかる 進化しつづける柔軟なアプリケーションの育て方
- 作者: Sandi Metz,?山泰基
- 出版社/メーカー: 技術評論社
- 発売日: 2016/09/02
- メディア: 大型本
- この商品を含むブログ (6件) を見る
継承
まずは継承のパターン。GenericParser
というクラスを継承したis-a関係のJsonParser
とXmlParser
を定義し、parse
メソッドをオーバーライドしている。
class GenericParser def parse raise NotImplementedError, 'Implementation required.' end end class JsonParser < GenericParser def parse # Jsonをパースする実装 end end class XmlParser < GenericParse def parse # XMLをパースする実装 end end parser = XmlParser.new parser.parse parser = JsonParser.new parser.parse
ダック・タイピング
つぎにダック・タイピング。ダック・タイピングでは、各パーサ実装はなんのクラスも継承せず、とにかくparse
というメソッドを持っているということだけが共通している。
class XmlParser def parse # Jsonをパースする実装 end end class JsonParser def parse # XMLをパースする実装 end end class GenericParser def parse(parser) parser.parse end end parser = GenericParser.new parser.parse(XmlParser.new) parser.parse(JsonParser.new)
実装の違い
- 継承 のコードでは、パーサを使う部分でそれが
XmlParser
なのかJsonParser
なのかが意識されてparse
メソッドが呼び出されている。 - ダック・タイピング のコードでは、
parse
メソッドを呼び出すGenericParser
は、そのメソッドを持つparser
が何かを意識していない。
ということが分かる。
継承によるコードは、それぞれのパーサが「誰なのか」(=なにを継承しているか)が分かることによって、パーサに何ができるか(どんなインターフェースを持っているか)を判断できる。一方で、ダック・タイピングとはすなわち「誰か」ではなく「何をするか」によってオブジェクトを見分けるため、パーサがparse
メソッドを呼び出せるということを期待するだけでインターフェースは意識しない。
ダック・タイピングとポリモーフィズムの関係
「なるほど、ということはダック・タイピングはポリモーフィズムのサブセットなのだろうか?」 という疑問が湧いてくる。
これまで自分は、ポリモーフィズムとはis-a関係にある継承クラスが抽象クラスと共通したインターフェースで個々の振る舞いを特化したものに変えること、というような理解をしていた。なので、必ずしも共通したインターフェースが保証される関係ではないダック・タイピングはポリモーフィズムに該当しないと考えていたわけだ。だがWikipediaのポリモーフィズムのページによると、ダック・タイピングは動的ポリモーフィズム(英: Runtime Polymorphism)というものに該当するようだ。この意味では、ダック・タイピングは継承に並んでポリモーフィズムを実現するための手段であると言っても良いのではないかと思う。
とはいえ、Googleでポリモーフィズムとダック・タイピングについて調べるとStackoverflowの質問がそこそこヒットするが、回答者によってポリモーフィズムとダック・タイピングの関係をどう捉えるかというのは割れているように見える。ある人は 「ダック・タイピングはポリモーフィズムするための方法の一つで間違いないよ」 と言ったり、またある人は 「ポリモーフィズムはインターフェースによる明示性(explicitness)を必要をするものだからダック・タイピングは違う」 と言ったりしている。やはり、これに関してはもう少しOOPの原典的なものにあたったほうがいいのかもしれない。