2週間ほど前にGois Godを始めて、言語の特徴として継承がないことに驚いた。
今まで触れてきた言語は皆オブジェクト指向で継承システムを有していたので、新しい言語(2000年以降に開発された言語を指す)が継承をサポートしていないことに違和感を覚えたのである。
しかし、Goの理念やオブジェクト指向について理解を深めていくうちに、継承というシステムにいかに問題点が多いか気づかされ、自身の浅慮を思い知った。
- 継承の問題点
自分はまだまだ未熟で大きな声では言えないが、継承が「共通部分を再利用するためのシステム」という認識は「誤った認識」だと考えている。
入門書(入門サイト)がどのように継承を解説しているか十分な調査はしていないが、私が初学時に得たのはこの認識であった。
スーパークラス(親クラス、継承元)の設計は、サブクラス(子クラス、継承する側)の性質から抜き取ってはならないはずだ。
後々サブクラスと同列のクラスの実装を行う際、そのような設計を行っているとス―パークラスも書き換えなければならないからだ。
実際にはスーパークラスの書き換えが行われず、余計な機能が継承されてバグや解読不能なコードになっているのだろう。
Dog
クラスとCat
クラスを実装するからAnimal
を実装するというのはやってはいけないのである。
初めにAnimal
クラスが要請されて、その後Dog
クラスが要請されたならばDog
クラスはAnimal
クラスを継承すべきだろう。
犬と猫は走る
→おそらく動物には足があるだろうと、Animal
クラスで足を追加
→後々蛇クラスの実装が要請されてAnimal
クラスを継承
→足のある蛇の完成 or Animal
クラス及びそのサブクラスの変更要請
帰納から"真のスーパークラス”を作成するのはリスクの高い作業なのである。
継承の本質は演繹なのだ。
しかし、既存の継承には帰納からの設計を制限する機能はない。
- 共通部分の切り出し
具体例が追加されて共通部分が発生したならば、その部分を関数で切り出してしまえば良い。
最近はこの考えのもとプログラミングを行っている。
継承はメソッド存在の保証(抽象基底クラス)や独自の名前でラップするのに利用している(同じint型でも、それがIDを指すのか、重さを指すのか等を変数名ではなく型として書くため)。
Goではメソッド・プロパティの存在保証はインターフェイスによって行われる。