問題タブ [liskov-substitution-principle]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
aggregate - 基本クラスを拡張する集約クラス-LSPの違反?
ウィキペディアのリスコフの置換原則(LSP)
属性*を持つAlien
クラスがあるとします。ときどき、他のフィールド値でグループ化された、データベースからnumFingers
の合計を取得する必要があります。numFingers
このような場合、各レコードを個別に操作する必要はありませんが、属性を取得したり、基本的なロジックを実行したりできるなど、多くの機能にアクセスする必要があります。これには、数千から合計されたデータが含まれる場合があります。レコードなのでAlien
、データベースクエリが合計の作業を実行できるときに、何千ものオブジェクトをインスタンス化することはほとんど意味がありません。
AlienAggregate
グループ化および合計されたクエリから属性が設定される、という拡張クラスを作成したいと思います。このクラスを使用すると、の任意Alien
のメソッドを呼び出すことができます。2つのクラスの機能の唯一の違いは、ですGetID()
。そのデータは任意の数のレコードから派生しているため、集約クラスにはIDがありません。GetID()
このため、 onを呼び出すとAlienAggregate
例外がスローされます。
これはリスコフの置換原則の違反ですか?への呼び出しを処理するためのより良い方法はありGetID()
ますか?Alien
とAlienAggregate
クラスの関係を設計するためのより良い方法はありますか?
*実際の名前は、私ができるという理由だけで変更されている可能性があります。
inheritance - インスタンスをスーパータイプとして宣言するのに、サブタイプとしてインスタンス化する理由と、リスコフの置換原則
私はここ数日、リスコフの置換原則を理解しようとしてきました。非常に典型的な長方形/正方形の例でいくつかのコードテストを行っているときに、以下のコードを作成し、それについて2つの質問を思いつきました。
質問1:スーパークラスとサブクラスの関係がある場合、インスタンスをスーパータイプとして宣言し、サブタイプとしてインスタンス化(新規作成)するのはなぜですか?
インターフェイスを介してポリモーフィズムを実行している場合、変数を次のように宣言してインスタンス化する理由を理解しています。
しかし、古いプログラミングクラスといくつかのブログの例でそれを思い出したので、継承を通じてポリモーフィズムを使用するとき、いくつかのコードがこのように変数を宣言するいくつかの例をまだ見ています
以下の私のコードでは、SquareはRectangleを継承しているため、次のように新しいSquareインスタンスを作成すると次のようになります。
それでも長方形として扱うことも、一般的な長方形のリストに追加することもできます。それでは、なぜ誰かがそれをRectangle = new Square()として宣言したいのでしょうか。私が見ていない利点、またはこれが必要となるシナリオはありますか?私が言ったように、以下の私のコードはうまく機能します。
}
これはリスコフの置換原則に違反しているはずですが、次の出力が得られます。
"幅:90、高さ:80
ConsoleApp.Program + Rectangle
幅:80、高さ:80
ConsoleApp.Program + Square
幅:80、高さ:80 ConsoleApp.Program + Square
質問2:では、なぜ、またはどのようにこのコードサンプルがLSPを破壊しているのでしょうか。すべての辺の正方形の不変量が等しいために、辺が独立して変更できるのは長方形の不変量を壊すだけですか?それが理由である場合、LSP違反は理論上のものにすぎませんか?または、コードで、このコードが原則を破っているのをどのように見ることができますか?
編集:私が読んでいたLSPブログ記事の1つで出てきた3番目の質問を思いついたが、答えがなかったのでこれだ
質問3:オープンクローズの原則は、新しいクラス(継承またはインターフェース)を通じて新しい動作/機能を導入する必要があると述べています。たとえば、基本クラスにWriteLogメソッドがあり、前提条件はありませんが、メソッドをオーバーライドする新しいサブクラスを導入しますが、イベントが非常に重要な場合にのみ実際にログに書き込みます。新しい意図された機能(サブタイプで強化されている前提条件)、それでもLSPを壊しているでしょうか?この場合、2つの原則は互いに矛盾しているように見えます。
前もって感謝します。
design-patterns - アダプターパターンとリスコフの置換
アダプタデザインパターンは、クラス(Target)のインターフェイスをクライアントが期待する別のインターフェイス(Adaptee)に変換するために使用されます。アダプタを使用すると、互換性のないクラスを連携させることができます。これは、互換性のないインターフェイスのために他の方法では機能しませんでした。
アダプタパターンは、継承(アダプタパターンのクラスバージョン)とコンポジション(アダプタパターンのオブジェクトバージョン)の2つの方法で実装できます。
私の質問は、継承を使用して実装されるアダプタパターンのクラスバージョンについてです。
図面エディタの例を次に示します。
TextViewクラスを再利用してTextShapeを実装したいのですが、インターフェイスが異なるため、TextViewオブジェクトとShapeオブジェクトを同じように使用することはできません。
シェイプインターフェイスに準拠するようにTextViewクラスを変更する必要がありますか?おそらくそうではありません。
TextShapeは、次の2つの方法のいずれかで、TextViewインターフェイスを図形のインターフェイスに適合させることができます。
- ShapeのインターフェースとTextViewの実装(Adapterパターンのクラスバージョン)を継承する
- TextShapeオブジェクト内にTextViewインスタンスを作成し、TextViewインスタンス(アダプタパターンのオブジェクトバージョン)を使用してTextShapeのインターフェイスを実装します。
クラスアダプタ
さて、質問です:-)。TextShapeはShape、特にTextViewから継承していますか?有効な「isa」関係ですか?そうでなければ、それはリスコフの置換原則に違反しませんか?
constructor - コンストラクターはリスコフの置換原則に準拠する必要がありますか?
私は通常、オブジェクトインスタンスがリスコフの置換原則に準拠していることを確認しようとしますが、LSPはコンストラクターにも適用されるべきだと人々は考えているのでしょうか?
私はこれをグーグルで試しましたが、どちらにしても強い意見を見つけることができませんでした。
私のコーディングのほとんどはRubyで行われていることに注意する必要がありますが、サブクラスのコンストラクターが親クラスとわずかに異なる場合があります。それらは同じ基本セットの引数を取り、多くの場合余分な引数を取ります。これは、他のクラスメソッドでも発生する場合があります。
私の頭の後ろでは、これは常にLSP違反のように感じていましたが、他の誰かもこのように感じているかどうかを確認したいと思いました。
java - Liskov Substitution Principleの私の講師の定義は間違っていますか、それとも誤解していますか?
以下は、(Liskov) 置換の原則により機能します。これは、特定のクラスのインスタンスの参照が期待される場合、そのクラスの任意のサブクラスのインスタンスへの参照を置き換えることができるというものです。
さて、私が理解している限り、この場合、Cat
オブジェクトを作成しています(したがって、ヒープにメモリ空間が作成されています)。次に、「felix」というオブジェクト参照変数を新しく作成したオブジェクトに割り当てていCat
ます。参照変数のタイプCat
は であるため、Cat
と のサブクラスのみを制御できCat
ます。
Object
次に、 type の参照変数を作成し、Object
それを felix( Cat
) オブジェクトに向けます。これは機能しますが、JVM が type の felix オブジェクトを認識するObject
ようになったため、機能が制限されますpurr()
。Cat
クラス、フェリックスはそれを使用できなくなります。
したがって、 type の参照が期待されますが、Cat
cat 型のスーパークラス (上記の定義で述べたサブクラスではなく) の参照を提供しています。これは許可されていますが、機能は制限されています (キャストを実行しない限り)。 )。
私は正しいですか?
c# - 配列が IList を実装する理由
System.Arrayクラスの定義を参照してください
理論的には、私はこれを少し書いて幸せになるはずです
iList から任意のメソッドを呼び出すこともできるはずです
私の質問は、例外が発生する理由ではなく、なぜ Array が IList を実装するのかということです。
stack - スタック、有界スタック、Liskov 置換プロパティ
Liskov置換プロパティに違反することなく、境界付きスタックデータ構造(上限のあるスタック)を従来のスタックのサブタイプとして実装できますか?
従来のスタックは制限付きスタックの代わりに使用できますが、制限付きスタックは、制限が十分に大きい場合にのみ、従来のスタックの代わりに使用できます。私はこの考えで正しいですか?
liskov プロパティは逆に真ですか?
ありがとう。
java - 抽象プロパティはリスコフ置換原理に違反しますか?
次のような抽象クラスがあるとします。
私のプログラムはPet
、特別な処理フラグが設定されているかどうかに応じて、 s を異なる方法で扱います。私の質問は、これが次のように述べている Liskov 置換原則に違反していると見なされるかどうかです。
[...]コンピュータプログラムでは、SがTのサブタイプである場合、タイプTのオブジェクトはタイプSのオブジェクトに置き換えることができます[...]そのプログラムの望ましいプロパティ(正確さ、実行されるタスク)を変更することなくなど)。
java - 継承とLSP
長い間ご質問をお詫び申し上げます。フィードバックはここで特に高く評価されます。。。
私の仕事では、日付範囲(必要に応じて日付期間)を使用して多くのことを行います。あらゆる種類の測定を行い、2つの期間の重複を比較する必要があります。インターフェイス、基本クラス、およびこれまでのニーズに対応するいくつかの派生クラスを設計しました。
- IDatePeriod
- DatePeriod
- CalendarMonth
- CalendarWeek
- 会計年度
本質を取り除いたDatePeriodスーパークラスは次のとおりです(このクラスのセットが必要な理由の基礎となるすべての魅力的な機能を省略しています...):
(Java擬似コード):
基本クラスには、期間クラスを操作するためのかなり特殊なメソッドとプロパティが多数含まれています。派生クラスは、問題の期間の開始点と終了点が設定される方法のみを変更します。たとえば、CalendarMonthオブジェクトが実際に「is-a」DatePeriodであることは私には理にかなっています。ただし、明らかな理由により、暦月は固定期間であり、特定の開始日と終了日があります。実際、CalendarMonthクラスのコンストラクターはスーパークラスのコンストラクターと一致しますが(startDateパラメーターとendDateパラメーターがあるという点で)、これは実際には、単一のCalendarオブジェクトのみを必要とする単純化されたコンストラクターのオーバーロードです。
CalendarMonthの場合、任意の日付を指定すると、CalendarMonthインスタンスが問題の月の最初の日に始まり、同じ月の最後の日に終わります。
長い前文をお詫びします。上記の状況を考えると、このクラス構造はリスコフの置換原則に違反しているように思われます。より一般的なDatePeriodクラスを使用する可能性がある場合は、CalendarMonthのインスタンスを使用できますが、主要なメソッドの出力動作は異なります。つまり、特定の状況でCalendarMonthのインスタンスを使用していることに注意する必要があります。
CalendarMonth(またはCalendarWeekなど)は、基本クラスでのIDatePeriodの使用によって確立されたコントラクトを順守しますが、CalendarMonthが使用され、単純な古いDatePeriodの動作が予想される状況では、結果がひどく歪む可能性があります。。。(基本クラスで定義されている他のすべてのファンキーなメソッドは正しく機能することに注意してください。CalendarMonthの実装で異なるのは開始日と終了日の設定のみです)。
使いやすさを損なうことなく、および/またはコードを複製することなく、LSPへの適切な順守が維持されるようにこれを構造化するより良い方法はありますか?