クラスはそのサブクラスを知る必要がありますか?


24

クラスはそのサブクラスを知る必要がありますか?たとえば、クラスは特定のサブクラスに固有の何かを行う必要がありますか?

私の本能は、それは悪いデザインであり、ある種のアンチパターンのように思えます。


6
通常はありませんが、特別な場合には役立ちます。
CodesInChaos

ある「リスコフの置換原則」または時々ちょうどLSP、でそれについて読む:アンチパターンと呼ばれるよく知られた1 en.wikipedia.org/wiki/Liskov_substitution_principle
ジミー・ホッファ

5
@JimmyHoffa-「Liskov Substitution Principle」はアンチパターンの名前ではありません。アンチパターンはLSPに違反する可能性がありますが、これがここで当てはまるかどうかは定かではありません。型がサブタイプを認識している場合でも、サブタイプを親の代わりに反分散と共分散で置き換えることができます。
マシューフリン

4
@MatthewFlynnおそらく私はLSPを少し緩く使用していますが、私の定義では、すべてがLSPに準拠している互いの要件を満たしているという事実ではなく、互いに同意するだけでなく、 LSPに違反しない別のサブクラスを実装できます。階層が自己認識型である場合、外部実装は基本クラスを変更せずにLSPを満たすことはできません。おそらくそれは厳密にLSPではありませんが、非常に近いです。そして、はい、LSP 違反はアンチパターンであると言うべき
ジミー・ホファ

2
これに何度か遭遇したとき、その知識をサブクラスでオーバーライドできるメソッドにリファクタリングしました(抽象クラ​​スまたは純粋仮想クラスにすることで強制するか、オーバーライドできる適切なデフォルト実装を提供します)。

回答:


32

クラスの概念によって暗示される答えは「いいえ」です。

処理しているアクション、データ、またはリレーションがすべてのサブクラスの一部である場合、実際の型を確認せずにスーパークラスで処理する必要があります。または、一部のサブクラスにのみ適用されます-実行時の型チェックを実行して正しいことを行う必要があり、他の誰かがそれを継承するたびにスーパークラスを変更する必要があります(または静かに間違ったことをする可能性があります)派生クラスの変更は、変更されていないスーパークラスなどを壊す可能性があります。

要するに、多くの悪い結果をもたらしますが、それは通常、そのような解決策を手に負えないほど十分に悪いものです。複数のサブクラスが同じことを行い、コードの重複を避けたい場合(実際には常に良いことです)、より良い解決策は、すべてのサブクラスがコードを継承できる中間レベルのクラスを導入することです。


4
この規則の1つの例外:クラスのドキュメントには、独自のライブラリにローカルなサブクラスをリストする必要があります。
キヴェーリ

3
@Kieveli ...その文書が最新である限り。
ムーヴィシエル

14
使用可能なドキュメント作成ツールは、継承ツリーを描画できるはずです
...-johannes

13
私はそれが例外だとは思わない。クラスはまだ何も知りません。ドキュメントは知っています。
ホンザブラベック

4
@Kieveliうーん完全に同意ません。
ジミーホッファ

16

だけでなく、必要があり、それは知りません、それは単にすることはできません!通常、クラスはいつでもどこでも拡張できます。作成された時点では存在していなかったクラスによって拡張できます。

一部の言語では、拡張クラスをスーパークラスで制御できます。Scalaでは、クラスをとしてマークできますsealed。これは、同じコンパイル単位(ソースファイル)内の他のクラスによってのみ拡張できることを意味します。それらのサブクラスがある場合を除きしかし、また sealedあるいはfinal、サブクラスは、その後さらに他のクラスによって拡張することができます。

Scalaでは、これは閉じた代数データ型のモデル化に使用されるため、標準的なHaskell List型は次のようになります。

data List a = Nil | Cons a (List a)

次のようにScalaでモデル化できます。

sealed trait List[+A]

case object Nil extends List[Nothing]

final case class Cons[+A] extends List[A]

そして、あなたはそれを保証できるだけので、それら二つのサブ「クラス」が存在しListているsealedため、ファイルの拡張外にすることはできません、Consですfinalので、すべての延長とすることができないNilobject、とにかく拡張することができません。

しかし、これは特定のユースケース(継承による代数的データ型のモデリング)であり、この場合でも、スーパークラスは実際にはそのサブクラスについては知りません。これは、より多くのことを保証していたユーザList彼はのケース差別をした場合、その種類NilCons、任意のは存在しません、他の背中の後ろに飛び出る代替。


多くの言語で機能するのは、何らかの形式のabstract internalメンバーを追加することです。
CodesInChaos

4

簡単な答えはいいえです。

コードが脆弱になり、オブジェクト指向プログラミングの2つの基本原則が損なわれます。

  • リスコフ置換の原理
  • オープンクローズの原則

1

はい、時々。たとえば、限られた数のサブクラスが存在する場合。ビジターパターンは、このアプローチの有用性の説明図です。

例:明確に定義された文法の抽象構文ツリー(AST)ノードは、Nodeすべてのノードタイプを処理するビジターパターンを実装する単一のクラスからすべて継承できます。


9
いいえ、いいえ、いいえ。これは有用ではなく、決して良い解決策ではありません。
サルタン

@Sulthan私は教室の外でASTを扱ってきましたが、ロルスは質問を本当に理解していないと思います。訪問者はAST上のノードのタイプではなく、別個のオブジェクトです。文法オブジェクトについて知ることができ、知っておくべきです。しかし、高レベルのASTノードはそうすべきではありません。

1
@JohnGaughan「知っている」という言葉は私を混乱させます。Nodeもちろん、基本クラスには、そのサブクラスへの直接参照は含まれていません。ただしacceptVisitorパラメータを持つメソッドが含まれています。そして、Visitor含まれているvisit各サブクラスごとにメソッドを。そのNodeため、サブクラスへの直接参照はありませんが、Visitorインターフェースを介して間接的にサブクラスを「認識」します。それらはすべてそれを介して結合されました。
ロラス

1
@スルタン決して言ってはいけない。オプションタイプは、supreclassが子孫について知っている場合の有効な例です。しかし、ヨルグが言ったように、封印されているとマークされます。
パベルボロニン

それから同意している:訪問者は訪問しているものを知る必要がある。

1

ある企業向けにコンポーネントを作成し、後で退職した後、誰かがそれを自分の目的に合わせて拡張した場合、そのことを通知する必要がありますか?

いや!

クラスでも同じです。あなたの本能を信頼。


雇用保障???
-sixtyfootersdude

あなたの60フィートの高さなので、私はあなたと議論しないでください:-)しかし、私が行って別の仕事を得た後、私の意味があったことを願っています。
ダニエルホリンレイク
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.