継承、親子、オーバーライド
-
11-07-2019 - |
質問
私が読んでいるOOPの本でこの引用に出会っただけです
子は拡張のみ許可されます 機能性と追加機能。 子供は削除できません 機能。あなたがそれを見つけた場合 子供は機能を削除する必要があり、 これは、子供が の親の前に表示する必要があります 継承階層!
しかし、私の質問は、これがオーバーライドの機能ではないかということです
解決
オーバーライドにより機能を削除できます。ただし、通常はこれを使用して動作を変更します。クラスが本来の動作をするようにします。
振る舞いが削除された場合、それは非常に多くの場合、悪いクラス設計の兆候です。
他のヒント
子は機能を削除できません-機能を変更できますが、たとえば、パブリックメソッドをプライベートにすることはできません。
継承のポイントは、子を親であるかのように処理できることです。 「Person」スーパークラスと「Employee」サブクラスがある場合、Employeeクラスにbreathe()メソッドがないことは意味がありません。
メソッドをオーバーライドする場合、オーバーライド中のある時点で親実装を呼び出すことができるため、オーバーライドを使用して親実装に機能を追加します。
いいえ。実際には、機能を拡張することになります(否定的な方法で)
新しい機能は「何もしない」としましょう。ただし、コードのクライアントに表示されるメソッドは、同じインターフェース
です。親のメソッドを削除するサブクラスを持つことはできません。
これは可能です
class Parent {
public void method_one(){
print "Hello";
}
}
class Child extends Parent {
public void method_one(){
// do nothing
}
}
しかし、これはそうではありません:
class Parent {
public void method_one(){
print "Hello";
}
}
class Child extends Parent {
// Attempt remove the method visibility, thus remove funcionality
private void method_one(){
// do nothing
}
}
それが、オーバーライド(および一般に仮想メンバー)が非常に慎重に行われるべき理由です... 実際、一般的に、オーバーライドするときは、派生クラスの実装が最初に基本実装を呼び出してから、追加機能を実行するように、基本クラスと派生クラスの両方をコーディングする必要があります...
しかし、この原則はオブジェクト指向言語では強制されず、しばしば違反されます...
これが悪い理由の例
CompanyAデザインタイプ(クラス)電話があると想像してください
namespace CompanyA {
class Phone {
public void Dial() {
// do work to dial the phone here
}
}
}
iagine Company Bは、Aタイプの電話を基本タイプとして使用する別のタイプのBetterPhoneを定義していません...
namespace CompanyB {
class BetterPhone: CompanyA.Phone {
public void Dial() {
Console.WriteLine("BetterPhoneDial");
EstablishConenction();
base.Dial();
}
}
}
現在、電話クラスが他の会社(会社C、Dなど)によって使用されているCompanyAは、接続を確立することがクラス内で有用であると判断し、EsatblishCOnnection()を追加してCompanyA.Phoneを変更します。メソッドも、おそらく異なる実装で...「新しい」ができるまでキーワード、このシナリオでは、CompanyBのBetterPhoneクラスが壊れていました。新しいベースクラスを初めて使用しようとしたときです。
子供が親の機能を削除する必要がある場合、親をインターフェイスとして宣言する必要があります。 インターフェイスは、その実装者に従う必要があるコントラクトを定義するメカニズムであるため。
E.g。
public interface IContract
{
void DoWork();
}
public class BaseContract: IContract
{
public virtual void DoWork()
{
//perform operation A
}
}
新しいEnhancedContractクラスを宣言する場合は、要件に応じてBaseContractまたはIContractから派生できます。 baseの操作Aに追加の操作を行いたい場合は、以下に示すようにBaseContractから継承できます。
public class EnhancedContract: BaseContract
{
public override void DoWork()
{
//perform operation B
base.DoWork();
//perform operation C
}
}
ただし、EnhancedContractのDoWorkメソッドで操作Aを実行することに興味がない場合は、IContractから継承します。
これにより、EnhancedWorkはDoWork()を実行しますが、その中で「操作A」を実行することは保証されません。
public class EnhancedWork:IContract
{
public void DoWork()
{
//perform operation D
}
}
これは、ユーザーが下にキャストすることを止めるため、アンダースタディングにとって重要です。
EnhancedContract e = new EnhancedContract();
BaseContract b = e;
継承の経験則は「追加機能を既存のものに追加する」です。