私が読んでいる OOP の本でこの引用に出くわしました。
子供は、機能を拡張し、機能を追加することのみが許可されています。子供が機能を削除することは決して許可されていません。子が機能を削除する必要があることがわかった場合、これは、子が継承階層で親の前に表示される必要があることを示しています。
しかし、私の質問は、これがオーバーライドの機能ではないでしょうか?
私が読んでいる OOP の本でこの引用に出くわしました。
子供は、機能を拡張し、機能を追加することのみが許可されています。子供が機能を削除することは決して許可されていません。子が機能を削除する必要があることがわかった場合、これは、子が継承階層で親の前に表示される必要があることを示しています。
しかし、私の質問は、これがオーバーライドの機能ではないでしょうか?
オーバーライドで機能を削除できます。しかし、通常は動作を変更するために使用します。クラスが本来あるべきように動作できるようにします。
動作が削除された場合、それは多くの場合、クラスの設計が不適切であることを示しています。
子は機能を削除できません。変更することはできますが、パブリック メソッドをプライベートにすることはできません。
継承のポイントは、子を親のように扱えることです。「Person」スーパークラスと「Employee」サブクラスがある場合、Employee クラスに Breath() メソッドがないと意味がありません。
メソッドをオーバーライドする場合、オーバーライド中のある時点で親実装を呼び出すことができるため、オーバーライドを使用して親実装に機能を追加します。
いいえ。実際には、機能を拡張することになります(否定的な方法で)
あなたの新しい機能が「何もしない」としましょうが、メソッド、コードのクライアントが見るものはまだ同じインターフェースです
親のメソッドを削除するサブクラスを持つことはできません。
これは可能です
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 が Type ( class ) Phone を設計しているとします。
namespace CompanyA {
class Phone {
public void Dial() {
// do work to dial the phone here
}
}
}
いいえ、会社 B は、会社 A の Phone を基本型として使用する別の型 BetterPhone を定義しています...
namespace CompanyB {
class BetterPhone: CompanyA.Phone {
public void Dial() {
Console.WriteLine("BetterPhoneDial");
EstablishConenction();
base.Dial();
}
}
}
ここで、Phone クラスが他の企業 (C 社、D 社など) によって使用されている CompanyA は、クラスで接続を確立することが有用であると判断し、CompanyA.Phone を変更して、EsatblishCONnection() メソッドも追加します。 、おそらく別の実装で...「new」キーワードができるまで、このシナリオはCompanyBのBetterPhoneクラスを壊していたでしょう...彼らが新しい基本クラスを初めて使用しようとしたとき。
子が親の機能を削除する必要がある場合は、親を Interface として宣言する必要があります。インターフェイスは、その実装者が遵守しなければならない契約を定義するメカニズムであるためです。
例えば
public interface IContract
{
void DoWork();
}
public class BaseContract: IContract
{
public virtual void DoWork()
{
//perform operation A
}
}
新しい EnhancedContract クラスを宣言する場合は、必要に応じて BaseContract または IContract から派生させることができます。ベースの操作 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;
Open Closed の原理、Liskov の置換原理を理解する上で、これらの操作はすべて重要であると考えています。
継承の経験則は、「既存の機能に追加の機能を追加する」です。