14

LSPは、「派生型は基本型の動作を変更してはならない」、つまり「派生型は基本型と完全に置き換え可能でなければならない」と述べています。

これは、基本クラスで仮想メソッドを定義すると、この原則に違反したことを意味します。

また、newキーワードを使用してdriveメソッドのメソッドを非表示にすると、この原則に違反します。

言い換えれば、ポリモーフィズムを使用すると、LSPに違反したことになります。

多くのアプリケーションで、基本クラスで仮想メソッドを使用しましたが、LSPに違反していることに気付きました。また、テンプレートメソッドパターンを使用する場合、私が頻繁に使用したこの原則に違反しています。

では、継承が必要で、ポリモーフィズムの恩恵も受けたい場合に、この原則に準拠するアプリケーションを設計するにはどうすればよいでしょうか。よくわかりません!

ここからの例を参照してください:http ://www.oodesign.com/liskov-s-substitution-principle.html

4

6 に答える 6

9

Barbara Liskovは、非常に優れた記事Data Abstraction and Hierarchyを公開しており、特にポリモーフィックな動作と仮想ソフトウェアの構築に触れています。この記事を読んだ後、彼女はソフトウェアコンポーネントが単純なポリモーフィック呼び出しから柔軟性とモジュール性を実現する方法を深く説明していることがわかります。

LSPは、抽象化ではなく、実装の詳細について述べています。具体的には、タイプのインターフェイスまたは抽象化を使用する場合はT、のすべてのサブタイプを渡すことを期待し、予期しない動作やプログラムのクラッシュ Tを観察しないようにする必要があります。

ここでのキーワードは、プログラムの任意のプロパティ(正確性、実行されたタスク、返されたセマンティクス、一時的なものなど)を記述できるため、予期しないものです。したがって、メソッドを作成することvirtual自体が違反することを意味するのではありませんLSP

于 2013-01-18T17:02:33.167 に答える
3

「派生型は基本型の動作を変更してはならない」とは、基本型を使用しているかのように派生型を使用できる必要があることを意味します。たとえば、電話をかけることができる場合は、x = baseObj.DoSomeThing(123)も呼び出すことができる必要がありますx = derivedObj.DoSomeThing(123)。基本メソッドが例外をスローしなかった場合、派生メソッドは例外をスローしないはずです。基本クラスを使用するコードは、派生クラスでもうまく機能するはずです。別のタイプを使用していることを「確認」するべきではありません。これは、派生クラスがまったく同じことをしなければならないという意味ではありません。それは無意味でしょう。言い換えると、派生型を使用しても、基本型を使用してスムーズに実行されていたコードが破損することはありません。

例として、コンソールにメッセージを記録できるようにするロガーを宣言したと仮定しましょう。

logger.WriteLine("hello");

ログを生成する必要があるクラスでコンストラクターインジェクションを使用できます。これで、コンソールロガーを渡す代わりに、コンソールロガーから派生したファイルロガーを渡します。ファイルロガーが「メッセージ文字列に行番号を含める必要があります」という例外をスローした場合、LSPが破損します。ただし、ログがコンソールではなくファイルに送られることは問題ではありません。つまり、ロガーが呼び出し元に対して同じ動作を示した場合、すべてが正常です。


次のようなコードを作成する必要がある場合は、LSPに違反します。

if (logger is FileLogger) {
    logger.Write("10 hello"); // FileLogger requires a line number

    // This throws an exception!
    logger.Write("hello");
} else {
    logger.Write("hello");
}

ちなみに、newキーワードはポリモーフィズムに影響を与えません。代わりに、基本タイプのメソッドと同じ名前を持っているが、それに関連していない完全に新しいメソッドを宣言します。特に、ベースタイプで呼び出すことはできません。ポリモーフィズムが機能するには、overrideキーワードを使用する必要があり、メソッドは仮想である必要があります(インターフェイスを実装している場合を除く)。

于 2013-01-18T17:11:21.900 に答える
2

リスコフの置換原則(LSP)は、主に、子クラスとは異なる可能性のある関数の実装を移動し、親クラスを可能な限り一般的にすることを目的としていると思います。

したがって、子クラスで変更したものが何であれ、この変更によって親クラスのコードを変更する必要がない限り、リスコフの置換原則(LSP)に違反することはありません。

于 2013-01-18T16:59:09.937 に答える
2

LSPは、スーパークラスを使用するのと同じ方法で派生クラスを使用できる必要があると述べています。「プログラム内のオブジェクトは、そのプログラムの正確性を変更することなく、サブタイプのインスタンスで置き換えることができる必要があります」そのルールを破る古典的な継承は、前者はを持っている必要Height = Widthあり、後者はを持っている可能性があるため、RectangleクラスからSquareクラスを派生させることHeight != Widthです。

public class Rectangle
{
    public virtual Int32 Height { get; set; }
    public virtual Int32 Width { get; set; }
}

public class Square : Rectangle
{
    public override Int32 Height
    {
        get { return base.Height; }
        set { SetDimensions(value); }
    }

    public override Int32 Width
    {
        get { return base.Width; }
        set { SetDimensions(value); }
    }

    private void SetDimensions(Int32 value)
    {
        base.Height = value;
        base.Width = value;
    }
}

この場合、WidthプロパティとHeightプロパティの動作が変更され、これはそのルールに違反しています。出力を取得して、動作が変更された理由を確認しましょう。

private static void Main()
{
    Rectangle rectangle = new Square();
    rectangle.Height = 2;
    rectangle.Width = 3;

    Console.WriteLine("{0} x {1}", rectangle.Width, rectangle.Height);
}

// Output: 3 x 2
于 2013-01-18T17:01:56.203 に答える
0

サブタイプは、基本タイプに置き換えることができる必要があります。

連絡先に関して。

派生クラスは、同じかそれより弱い場合は基本クラスの前提条件を、同じかそれ以上の場合は事後条件を置き換えることができます。

リンク

于 2013-01-18T17:02:02.810 に答える
-1

ポリモーフィズムが機能するには、LSPを順守する必要があります。それを打破する良い方法は、基本型にない派生型にメソッドを導入することです。その場合、これらのメソッドは基本型で使用できないため、ポリモーフィズムは機能しません。ポリモーフィズムとLSPの両方を順守しながら、メソッドの異なるサブタイプ実装を使用できます。

于 2013-01-18T17:03:10.713 に答える