LoginSignup
19

More than 5 years have passed since last update.

継承を捨てよう!

Posted at

初めに

継承ではなくインターフェースで行こうという話
(ボロカスに叩かれてもいいかなって言う気持ちで)

インターフェースと継承

そもそも、インターフェースと継承って何でしょうか。
一言で言うと、あるオブジェクト/クラスに対して「この機能(メソッド)がある」「このパラメータ(メンバ)がある」ということを保証するシステムです。
つまり、本質的には同じです。

違い

同じと言っても少しだけ違いがあります。とはいえ、どちらが得意かというだけの違いでしかありません。
継承では実装の無いのメソッド(純粋仮想関数)以外は実装を強制させられません。一方でインターフェースは宣言したメソッドすべての実装がありません。したがって、インターフェースを実装したクラスはそのインターフェースで宣言したメソッドを全て実装する必要があります。
つまり、継承はインターフェースに対して「すでに実装したコードをサブクラス側で記述する必要が無い」と言うメリットがあります。

ならインターフェースを使おうよ

しかし、この継承の「実体のあるメソッドをサブクラスのインスタンスを用いてコールできる」と言う点が問題を複雑化させます。
複数のクラスを継承(多重継承)したときに、メソッド名とシグネチャが衝突した場合に問題が起こってしまうのです(いわゆるダイヤモンド継承の問題)。
しかし、インターフェースは異なるインターフェース間でメソッドとシグネチャが衝突しても、実装は各クラス側に委ねられているので、実体が一つとなり、この問題が発生しません。
まとめると

継承:多重継承の問題があるけど、サブクラス側でいちいちメソッドを実装しなくていいよ。
インターフェース:多重継承の問題は無いけど、各クラスでいちいちメソッドを実装しないといけないよ。

と、言うことになります。一長一短で、どちらの短所についても本質的な解決は難しいですが、インターフェースの場合はこの短所をかなり軽減することが出来る方法があります。

解決策

解決策は非常に簡単で、外部のクラスにメソッドの実装を委譲してしまえばいいのです。そして、外部のクラスのメソッドではダメな場合は必要に応じて各クラスに応じた処理を実装すればいいわけです。
ちょうどこんな感じですね
InterFaceSample.png

こうしておけば、実際の標準的な処理をだらだらと複数のクラスにわたって記述することが無くなります。
継承において標準的な処理を1か所にまとめるのは本質的には保守性の観点からの要請なわけですから、この実装方法の場合、継承と比べて保守性が低下することはありません。

メンバ変数もインターフェース

メンバ変数もインターフェースに落とし込むことが出来ます。もちろん、通常のインターフェースでもメンバ変数を宣言できますが、その際の制約は複数のインターフェース間でメンバ変数の名前が衝突してはいけないということです(これは継承でも同じですが)。そこで、ゲッターとセッターをインターフェースで用意します。こうすることで各インターフェースを実装する個別のクラス側で制御することが出来るようになります。
InterFaceSample2.png

このあたりで

小ネタなので、この辺で終わりです。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19