スーパークラスへのダウンキャスティングにより、メソッドを無効にすることはできますか?
-
29-10-2019 - |
質問
次の質問に対する答えがすべての主要なOOP言語で同じかどうかを理解しようとしています。そうでない場合は、それらの言語がどのように異なりますか。
クラスがあるとします A
メソッドを定義します act
と jump
;方法 act
通話方法 jump
. A
のサブクラス B
オーバーライドメソッド jump
(つまり、適切な構文は、いつでもそれを確保するために使用されます jump
クラスの実装と呼ばれます B
使用されている)。
私はオブジェクトを持っています b
クラスの B
. 。クラスのように正確に振る舞いたい A
. 。言い換えれば、私は欲しい jump
実装を使用して実行されます A
. 。さまざまな言語での私の選択肢は何ですか?
たとえば、何らかの形のダウンキャスティングでこれを達成できますか?または、どのメソッドを呼び出すかを知っているプロキシオブジェクトを作成することによって?
クラスの真新しいオブジェクトの作成を避けたい A
そして、間に内部状態の共有を慎重に設定する a
と b
それは明らかに将来の防止ではなく、複雑ではないからです。私もの状態をコピーすることを避けたいと思います b
クラスの真新しいオブジェクトに A
コピーするデータがたくさんあるかもしれないからです。
アップデート
この質問をしました 特にPythonについて, しかし、これはPythonで達成することは不可能だと思われます そして技術的にはそれを行うことができます...ちょっと..
技術的な実現可能性とは別に、デザインの観点からこれを行うことに強い議論があるようです。私はそれについて尋ねています 別の質問.
解決
コメントは繰り返しました:継承よりも構成を好む。
サブクラスがスーパークラスからの行動の違いが明確に定義されている場合、継承はうまく機能しますが、そのモデルが厄介になったり、意味をなさないポイントに到達することがよくあります。その時点で、デザインを再考する必要があります。
構成は通常、より良い解決策です。オブジェクトのさまざまな動作を異なるオブジェクト(またはオブジェクト)に委任すると、サブクラス化の必要性が低下または排除される場合があります。
あなたの場合、クラスAとクラスBの行動の違いは、戦略パターンにカプセル化される可能性があります。次に、単に新しい戦略を割り当てるだけで、インスタンスレベルでクラスA(およびクラスB)の動作を変更できます。
戦略パターンでは、短期的にはより多くのコードが必要になる場合がありますが、クリーンで保守可能です。スウィズリング、モンキーのパッチ、および特定の言語の実装で私たちが突くことができるすべてのクールなものは楽しいですが、予期しない副作用の可能性が高く、コードを維持するのが難しい傾向があります。
他のヒント
あなたが尋ねているのは、OOPプログラミングによって完全に無関係/サポートされていません。
オブジェクトをサブクラス化する場合 A
クラスで B
具体的なインスタンスが B
次に、ベースメソッドのすべてのOverriden/新しい実装がそれに関連付けられている(Virtual TablesなどのJavaまたはC ++について話します)。
インスタンス化されたオブジェクトがあります B
.
その方法があふれている場合、なぜスーパークラスの方法を呼び出すことができる/すべきだと期待するのでしょうか?
もちろん電話をかけることで、それを明示的に呼び出すことができます super
メソッド内では、自動的にそれを行うことはできません。キャストもそれを行うのに役立ちません。
なぜあなたがそれをしたいのか想像できません。
クラスを使用する必要がある場合 A
次に、クラスを使用します A
.
その機能をオーバーライドする必要がある場合は、そのサブクラスを使用します B
.
ほとんどのプログラミング言語は、仮想関数の動的ディスパッチをサポートするためにいくつかのトラブルに陥ります(オーバーライドされた方法を呼び出す場合 jump
親クラスの実装の代わりにサブクラスで) - それを回避したり、それを避けたりすることは難しい程度です。一般に、専門化/多型は望ましい特徴です - おそらくそもそもOOPの目標です。
ウィキペディアの記事をご覧ください 仮想関数, 、多くのプログラミング言語での仮想関数のサポートの有用な概要を提供します。特定の言語を検討する際に開始する場所、およびプログラマーがディスパッチの動作を制御できる言語を見るときに計量するトレードオフを提供します(たとえば、C ++のセクションを参照)。
だから、あなたの質問に対する答えは、「いいえ、行動はすべてのプログラミング言語で同じではない」ということです。さらに、言語に依存しないソリューションはありません。 C ++は、あなたが最善の策かもしれません 必要 動作。
実際にこれをPython(一種)で行うことができ、ひどいハックを使用できます。最初のPython固有の質問で議論していたラッパーのようなものを実装する必要がありますが、 bのサブクラスとして. 。次に、書き込みプロキシも実装する必要があります(ラッパーオブジェクトには、クラス階層に通常関連付けられている状態を含めるべきではありません。すべての属性アクセスをBの基礎となるインスタンスにリダイレクトする必要があります
しかし、メソッドの検索をaにリダイレクトしてから、ラップされたインスタンスでメソッドを呼び出すのではなく、ラッパーオブジェクトを渡すメソッドを呼び出します。 self
. 。ラッパークラスはBのサブクラスであるため、これは合法です。したがって、ラッパーインスタンスは、あなたが呼んでいるメソッドのクラスのインスタンスです。
これは非常に奇妙なコードであり、IS-AとHAS-Aの両方の関係を同時に使用してクラスを動的に生成する必要があります。また、おそらくかなり壊れやすくなり、多くのコーナーケースで奇妙な結果が得られます(この種の奇妙なことが可能であるため、Pythonで100%完璧なラッパークラスを書くことはできません)。
私は完全に天気を捨てておきます。これは良い考えかどうかです。