継承
inheritance
#WIP
継承のダメさ、変更の手間の問題もありそうと思ったmrsekut.icon
https://mametter.hatenablog.com/entry/2024/02/10/120527
一つメソッドを生やすときの手間と、
継承されたものを分離して正しい形するための手間
が全く釣り合ってないのでは
(具体例を考えずに感覚で書いてるので全然そんなことない可能性はある)
知らないだけでIDEのサポートで簡単にできる可能性もある
Move to file的な
「継承」という構造(概念?)自体が悪いわけではないのだと思う
理論的にはそこそこ正しいんじゃないか、しらんけど
ただ、それを表現するツールがショボいのが悪いのだと思う
求められる制約が多かったり、それの違反に気付きづらすぎだったり、
違反に気付いても修正が面倒だったり、
overrideしてるものなのかどうかがひと目で判断できなかったり
プログラマの認知に負担をかける要素が多すぎるのだろう
新しい言語機能が発見されたり、IDEのサポートが強化されれば割と使えたりするのではないか
しらんけど
継承を使用できる条件
defaultのOOP言語機能として提供される「継承」を作るための制約が弱すぎるmrsekut.icon
だから何でもかんでも継承にすることができるし、
実際それは原則を守っていないので、ゆくゆく破滅するということが生じる
契約プログラミングがなく、動的型付け言語で、チーム開発している、というような状況で、正しく継承をやっていくってほぼ不可能じゃない?という気がするmrsekut.icon
継承を使用できる条件は暗黙的なものなので、破ろうと思えば簡単に破れる
単純に知識がなかったり、疲弊してて思考力が鈍ってたりすればいとも簡単に。
故に「継承は禁止」としたほうが安心安全運用になる
継承関係として定義すべきでないものの例
基本的なこと
code:ts
class P {
constructor() {..}
f() {..}
h() {..}
}
class C extends P {
constructor() {
..
super(..)
}
g() {..}
h() {..}
}
C.g()が呼ばれた場合は、普通にC内のg()が呼ばれる
C.f()が呼ばれた場合は、Cにはないので、親であるPへメッセージが移譲され、Pのf()が応答する
h()は親で定義されているが、子でも定義されている(override)ので、Cの方のh()が呼ばれる
overraideしているにも関わらず、親の同名のmethodを呼びたい場合は、super()で呼ぶ
constructor()でやっているのがそれ
constructor()も1つのmethodであり、別に特別扱いされているわけではない
instantiateする際は、親のpropertyなども初期化する必要があるので、constructorとsuperは割とセットで使われるだけ
クラスベースのOOPの継承
基本型 (basic type)の機能を受け継ぐ派生型 (derived type)を作る
#??
具体的に何が受け継がれる?
property, method全部?
methodなどは適当なアクセス修飾子を付けたら引き継がれない、みたいなのがあった気がする
再利用性以外の利点はなに?
継承って、継承しなくても、
子目線で、親となるはずだったものをDIして内部で使うこともできるはずだと思うけど、
わざわざ継承する嬉しさってなに #??
あまり具体的にイメージできてないが、継承するはずだった親classをDIして使おうとするとかなり冗長になっちゃったりするのか?
traitを使うか、super classを使うかの判断って何でするの?
behaves-like-aか、is-aか
sub classはsuper classの全ての振る舞いを継承する
から、それが正しい状況でないといけない
prototypeベースのOOPの継承
こっちは知らんmrsekut.icon
クローンすることのことらしい
『オブジェクト指向設計実践ガイド』.icon p.167~ 親子間の結合度の話
継承もObject間の依存なので、superを呼ぶときに、子は親のことを知りすぎてはいけない
superの返り値の型がstrirngなのか、objectなのかを知っていないと使えない
「superを送るのを忘れるとerrorになる」とか
フックメッセージを使って解決する
関連
Is-a関係
Has-a関係
コンポジション集約
#??
どこで継承を使うべきか?
継承元とはめちゃくちゃ密結合になるので、
継承元はほぼほぼ変更がないことを担保していて欲しい
hsの型クラスはかなり理想的mrsekut.icon
逆に、誤った継承を行ったことに依る地獄の例も見たい
よく転がっているはず
なんで地獄になるのか、リスコフの置換原則 (LSP)を守っていれば回避できていたのか
また、型クラスにおける継承では、こういった問題が生じることを目にしたことが無いがなぜか?
単純に知らないだけで問題は起きているパターン
自分で継承することは少ないから問題は起きづらいパターン
https://twitter.com/kawasima/status/1493880223984545794
このような(OOPでは失敗する)数学的な継承関係がうまく当てはまるから、というパターン
有名型クラスである、Monoid、Functorや、Monadとかは完全に数学的な構造に基づいて継承関係が決まっている
その他
どれ?
https://twitter.com/todokr/status/936923406724825090
https://twitter.com/kgtkr/status/1269200390995628032
参考
継承のことは忘れよう - オブジェクト指向プログラミングを極める
もっともなことを言っていると思うmrsekut.icon
https://ja.wikipedia.org/wiki/継承_(プログラミング)
https://qiita.com/tonluqclml/items/c0110098722763caa556
https://python.ms/composition-over-inheritance/#_1-合成と委譲
https://qiita.com/jesus_isao/items/c23ad5b4171a02b91627
https://ironoir.hatenablog.com/entry/2021/01/25/190000
https://www.infoworld.com/article/2073649/why-extends-is-evil.html
https://qiita.com/tonluqclml/items/c0110098722763caa556
https://qiita.com/tutinoco/items/6952b01e5fc38914ec4e#継承
https://iwatam-server.sakura.ne.jp/software/devintro/inheritance/index.html