16
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

悪い継承はどんな継承か(未完成)

Last updated at Posted at 2021-08-21

※ずっと下書きに入っててもったいないのでとりあえず公開

「継承ってあまりよくないよねー」と言ったような言説をここ数年で見かけるようになりました。
私も大体5年前くらいに継承という仕組みに対して失望しました。
とはいえ現状多くのプログラミングでは継承を多用しているはずで、継承=悪というのは乱暴だとも言えます。
ではどういう継承が悪いのか、継承のどういうところが悪いのかという話になると思いますが、これをスッと答えられる人は多くないのではないでしょうか?

私も言語化しづらいなーと思っていたのですが、普通にググってたら書いてたいたし、なんなら大昔からそんな事言われていたようなので、ざっくり調べました。
参考程度にどうぞ。
細かい話はしません、私には荷が重い。

前提として押さえておきたい文脈

これはあくまで「自分たちで作ったクラスを継承する」みたいな文脈です。
SDKやLibraryなどで慎重に設計されたクラスを継承することに対して「良くない」という声は上がっていない認識です。
そもそもそれ無いとなんもできません。

私が得意なiOSだと例えばBaseViewControllerみたいなのが話題の対象です。

オブジェクト指向のアンチパターン

サンキューWikipedia
Wikipedia - アンチパターン オブジェクト指向のアンチパターン

貧血ドメインモデル(英語版)
BaseBean(英語版)
スーパークラスの呼び出し(英語版)
円-楕円問題(英語版)
循環依存(英語版)
定数インターフェイス(英語版)
神オブジェクト(英語版)
オブジェクトのゴミ溜め(英語版)
オブジェクトの乱交状態(英語版)
シーケンスによる結合(英語版)
ヨーヨー問題

全てが継承に関わっているわけでは有りません。
関係ありそうなものを以下にまとめます。

ヨーヨー問題

Wikipedia - ヨーヨー問題

ソフトウェア開発におけるヨーヨー問題アンチパターンとは、プログラムを読んで内容を理解しようとしたときに、継承関係が深すぎる・複雑すぎるなどの理由で、たくさんのクラスを行ったり来たりしないと処理フローが追えない状況のことである。

補足・コメント
これめっちゃわかります。
私は特にライフサイクルが存在するプログラムにおいてこれを感じます。
処理のフローが、子のメソッド→親のメソッド→子のメソッドのようなフローを辿り、問題がどこでおきているのか追いづらくなると思います。

神クラスになってしまう

神クラス:設計の一部分(クラス)に、過剰に機能を集中させること
BaseBean:ユーティリティクラスに処理を委譲せず、継承して使ってしまうこと

ここらへん似た話だと思います。
神クラス、ゴッドクラス、あとはBlobって言葉も合ったと思います。
簡単に言えば1個のクラスに全機能を詰め込んでしまうことで起こる問題の総称です。

これがどう継承と関係しているのかといえば、ある種類のクラスの共通メソッドを作ろうとしたときに、親クラスを作り継承してしまうことがありますが、そこから神クラスができてしまうことがあるからです。
あるメソッド、処理を使いたい時は何でもかんでもそれを継承する羽目になりますから。

これは間違った継承の使い方ですね。

ライフサイクルが混ざっているものの継承

これは私の経験則です。
例えばiOSだとUIViewController, AndroidだとActivityのように、ライフサイクルが混ざってるクラスにおいて継承すると処理の順番が非常に複雑になりますしコントロールしづらくなります。

以下、まとめきれてないやつのメモ

スーパークラスの呼び出し(英語版)
サブクラスがスーパークラスのオーバーライドされたメソッドを呼び出さなければならないような設計

シーケンスによる結合(英語版)
メソッドが特定の順序で呼び出される必要のあるクラス

リスコフの置換原則
https://ja.wikipedia.org/wiki/%E3%83%AA%E3%82%B9%E3%82%B3%E3%83%95%E3%81%AE%E7%BD%AE%E6%8F%9B%E5%8E%9F%E5%89%87

開放/閉鎖原則
https://ja.wikipedia.org/wiki/%E9%96%8B%E6%94%BE/%E9%96%89%E9%8E%96%E5%8E%9F%E5%89%87

依存性逆転の原則
https://ja.wikipedia.org/wiki/%E4%BE%9D%E5%AD%98%E6%80%A7%E9%80%86%E8%BB%A2%E3%81%AE%E5%8E%9F%E5%89%87

継承
https://ja.wikipedia.org/wiki/%E7%B6%99%E6%89%BF_(%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0)
仮想継承にしていない場合に同一の基底クラスが複数存在してしまう(これが望ましい場面もあるが)。
これの何が問題かというと、最初は仮想継承していなかったものを、後から仮想継承にしたくなったときに、変更点を洗い出すのが大変になるからである。つまり仮想継承を使用するには設計をきちんと行う必要があるということである。
しかしながら多重継承を使う方が直感的になる場合もあるとの主張もあり、どちらが正しいとは言えない状況である。

解決策

限定多重継承
https://ja.wikipedia.org/wiki/Mixin

ここらへんもちゃんとまとめたいけど追いついていない(宿題)

雑感と教訓

業界全体が「完全に理解した」状態に陥って、実は全然理解できていないケースがあるので注意が必要。
Wikipediaに載ってるレベルの既知の事実を知らなかったりする。ヨーヨー問題とか、まさにそれじゃん!というのがいくらでもある。

我々がやってるのは理論ではなく工学なので、どうしてもある程度動くと理論を投げ出してしまうきらいがある。おかげで理論がまとまりきっていなく経験則や噂や意見しか見つからない。

こういうのがあるので、DDDやDIや関数型言語のような流行りにあまり乗り気になれない(言い訳)
学習コストってたぶん5年とか10年単位で掛かるんですよ。

(誰かまとめてくれないかなー)

16
11
5

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
16
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?