Richの代替原則であるOCPは、OOの高レベルの原則として、「抽象化」と「多型」の使用を提唱して、設計の静的構造を動的構造に変更して設計の囲いを維持します。 「要約」は、言語によって提供される関数です。 「多型」は、継承されたセマンティクスによって実装されています。
リヒター置換の原則には、次の4つの意味が含まれています。
これで、上記の4つの意味を説明できます。
サブクラスは、親クラスの抽象的なメソッドを実装できますが、親クラスの非アブストラクトメソッドを無効にすることはできません。
システムを設計するとき、インターフェイスまたは抽象クラスを設計することがよく、サブクラスが抽象的なメソッドを実装します。リヒター置換の原則は実際にここで使用されています。サブクラスが親クラスの抽象的な方法を実装できることを理解するのは簡単です。実際、サブクラスは、空のメソッドを記述したとしても、親クラスの抽象的な方法を完全に実装する必要があります。そうしないと、エラーをコンパイルして報告する必要があります。
リヒター置換の原則の重要なポイントは、親クラスの非アブストラクトメソッドをカバーできないことです。親クラスでよく実現された方法は、実際に一連の仕様と契約を設定することです。すべてのサブクラスにこれらの仕様に準拠するように強制するわけではありませんが、サブクラスがこれらの非抽象的メソッドを任意に変更する場合、継承システム全体に損傷を与えます。リズル置換の原則は、この意味を表しています。
オブジェクト指向のデザインのアイデアでは、この機能を継承することは、システムの設計に大きな利便性をもたらしますが、そこからいくつかのリスクもあります。次の例を使用して、相続のリスクを説明します。 2つの数値を差し引く機能を完了する必要があり、クラスAが責任を負います。
クラスA {public int func1(int a、int b){return ab; }} public class client {public static void main(string [] args){a a = new a(); System.out.println( "100-50 ="+A.Func1(100、50)); System.out.println( "100-80 ="+A.Func1(100、80)); }}実行結果:
100-50 = 50100-80 = 20
後で、新しい関数を追加する必要があります。2つの数値を追加してから100で合計すると、クラスBが責任を負います。つまり、クラスBは2つの機能を完了する必要があります。
2つの数字は減算します。
2つの番号を追加してから100を追加します。
クラスAは最初の関数を実装しているため、クラスBがクラスAを継承した後、2番目の関数を完了する必要があります。コードは次のとおりです。
クラスBはa {public int func1(int a、int b){return a+b; } public int func2(int a、int b){return func1(a、b)+100; }} public class client {public static void main(string [] args){b b = new b(); System.out.println( "100-50 ="+b.func1(100、50)); System.out.println( "100-80 ="+b.func1(100、80)); System.out.println( "100+20+100 ="+b.func2(100、20)); }}クラスBが完了した後、実行の結果:
100-50 = 150100-80 = 180100+20+100 = 220
元々実行されていた減算関数にはエラーがあることがわかりました。その理由は、クラスBがメソッドに名前を付けた場合、親クラスのメソッドを誤って書き換え、減算関数を実行するすべてのコードがクラスBの書き換え方法を呼び出し、元の正常関数のエラーを引き起こすためです。この例では、ベースクラスAによって完了した関数を参照し、サブクラスBに変更した後、例外が発生しました。実際のプログラミングでは、親クラスの方法を書き直すことで、多くの場合、新しい機能を完了します。簡単に書くことは簡単ですが、継承システム全体の再利用性は比較的低くなります。特に、多型がより頻繁に使用される場合、プログラム操作エラーの確率は非常に高くなります。親クラスの方法を書き直す必要がある場合、より一般的なアプローチは次のとおりです。元の親クラスと子のクラスは、より一般的な基本クラスを継承し、元の継承関係を削除し、代わりに依存関係、集約、組み合わせ、その他の関係を使用します。