継承階層でリスコフ置換原理を検証する方法は?


14

この答えに触発された:

リスコフの代替原則では

  • サブタイプでは前提条件を強化できません。
  • サブタイプでは事後条件を弱めることはできません。
  • スーパータイプの不変式は、サブタイプに保存する必要があります。
  • 履歴制約(「履歴ルール」)。オブジェクトは、そのメソッド(カプセル化)によってのみ変更可能と見なされます。サブタイプはスーパータイプには存在しないメソッドを導入する可能性があるため、これらのメソッドの導入により、スーパータイプでは許可されないサブタイプの状態変更が可能になります。これは履歴制約により禁止されています。

これらの4つのポイントに違反するクラス階層を誰かが投稿し、それに応じてそれらを解決する方法を誰かが投稿することを望んでいました。
階層内の4つのポイントのそれぞれを識別する方法と、それを修正する最良の方法について、教育目的で詳細な説明を探しています。

注:
私は人々が作業するためのコードサンプルを投稿したいと思っていましたが、問題自体は障害のある階層を特定する方法に関するものです:)


回答でLSP違反のいくつかの他の例があります。このSOの質問
StuartLC

回答:


17

それは、その引用がそれを音、正確にそのままにするよりもずっと簡単です。

継承階層を見るとき、基本クラスのオブジェクトを受け取るメソッドを想像してください。次に、このメソッドを編集する誰かがそのクラスにとって無効になる可能性のある仮定があるかどうかを自問してください。

例えば(元々はボブおじさんのサイトで見られた):

public class Square : Rectangle
{
    public Square(double width) : base(width, width)
    {
    }

    public override double Width
    {
        set
        {
            base.Width = value;
            base.Height = value;
        }
        get
        {
            return base.Width;
        }
    }

    public override double Height
    {
        set
        {
            base.Width = value;
            base.Height = value;
        }
        get
        {
            return base.Height;
        }
    }
}

十分公平だと思いますよね?Squareと呼ばれる特殊なRectangleを作成しました。これにより、Widthは常にHeightと等しくなければなりません。正方形は長方形なので、オブジェクト指向の原則に適合しますか?

しかし、待って、誰かがこのメソッドを書いたらどうなるでしょうか:

public void Enlarge(Rectangle rect, double factor)
{
    rect.Width *= factor;
    rect.Height *= factor;
}

クールではありません。しかし、このメソッドの作成者が潜在的な問題がある可能性があることを知っているはずの理由はありません。

あるクラスを別のクラスから派生させるたびに、基本クラスと、人々がそれについて何を想定するかを考えてください(「幅と高さがあり、両方とも独立している」など)。次に、「これらの仮定は私のサブクラスで有効なままですか?」そうでない場合は、設計を再考してください。


非常に良い例です。+1。できることは、EnlargeをRectangleクラスのメソッドにし、Squareクラスでオーバーライドすることです。
マルコ・fiset

@ marco-fiset:SquareとRectangleは分離され、1次元のみのSquareが表示されますが、それぞれがIResizableを実装しています。Drawメソッドがあった場合、それらは類似していることは事実ですが、共通のコードを含むRectangleDrawerクラスをカプセル化する方がよいでしょう。
pdr

1
これは良い例だとは思いません。問題は、正方形には幅も高さもないことです。それはちょうどその辺の長さを持っています。幅と高さが読み取り可能な場合のみ問題はありませんが、この場合は書き込み可能です。変更可能な状態を導入する場合、LSPを維持することは常にはるかに困難です。
SpaceTrucker

@pdr例に感謝しますが、私の投稿で言及した4つの条件に関して、Squareクラスのどの部分がそれらに違反していますか?
松o

1
@Songo:それは歴史の制約です。ここでより良い説明:blackwasp.co.uk/LSP.aspx「サブクラスには、その性質上、スーパークラスのすべてのメソッドとプロパティが含まれます。さらにメンバーを追加することもできます。履歴制約は、新規または変更されたメンバーが基本クラスで許可されない方法でのオブジェクトの状態。たとえば、基本クラスが固定サイズのオブジェクトを表す場合、サブクラスはこのサイズの変更を許可しないでください。」
pdr
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.