長方形から正方形を導出することは、リスコフ置換原理の違反ですか? [閉まっている]

StackOverflow https://stackoverflow.com/questions/1030521

  •  06-07-2019
  •  | 
  •  

質問

デザインの原則をデザインし、学習するのは初めてです。

長方形から正方形を導出することは、リスコフの代替原則に違反する典型的な例であると述べています。

その場合、正しいデザインはどうすればよいですか

役に立ちましたか?

解決

推論は次のようなものだと思います:

長方形を受け入れ、その幅を調整するメソッドがあるとします:

public void SetWidth(Rectangle rect, int width)
{
    rect.Width = width;
}

このテストに合格すると仮定するために、長方形が何であるかを考えると、完全に合理的でなければなりません:

Rectangle rect = new Rectangle(50, 20); // width, height

SetWidth(rect, 100);

Assert.AreEqual(20, rect.Height);

...長方形の幅を変更してもその高さに影響しないため。

ただし、Rectangleから新しいSquareクラスを派生したとしましょう。定義により、正方形の高さと幅は常に同じです。そのテストをもう一度試してみましょう:

Rectangle rect = new Square(20); // both width and height

SetWidth(rect, 100);

Assert.AreEqual(20, rect.Height);

正方形の幅を100に設定すると高さも変わるため、このテストは失敗します。

したがって、四角形から四角形を導出することにより、リスコフの置換原則に違反します。

「is-a」はルールは「現実の世界」で意味をなします。 (正方形は間違いなく長方形の一種です)が、ソフトウェアデザインの世界では常にそうとは限りません。

編集

あなたの質問に答えるために、正しい設計は、おそらく長方形と正方形の両方が共通の「ポリゴン」から派生することです。または" Shape"クラス。幅または高さに関するルールを強制しません。

他のヒント

答えは可変性に依存します。四角形と四角形のクラスが不変である場合、 Square は実際には Rectangle のサブタイプであり、最初から2番目から派生してもまったく問題ありません。そうしないと、 Rectangle Square の両方がミューテーターなしで IRectangle を公開する可能性がありますが、どちらのタイプも適切にサブタイプではないため、一方から他方を派生することは間違っています他の

四角形から四角形を導出することは必ずしもLSPに違反することに同意しません。

Mattの例では、幅と高さが独立していることに依存するコードがある場合、実際にはLSPに違反しています。

ただし、仮定を破らずにコード内のあらゆる場所で四角形を四角形に置き換えることができれば、LSPに違反することはありません。

つまり、あなたのソリューションでの抽象化矩形の意味になります。

最近、この問題に苦労していますが、リングに帽子を追加すると思いました:

public class Rectangle {

    protected int height;    
    protected int width;

    public Rectangle (int height, int width) {
        this.height = height;
        this.width = width;
    }

    public int computeArea () { return this.height * this.width; }
    public int getHeight () { return this.height; }
    public int getWidth () { return this.width; }

}

public class Square extends Rectangle {

    public Square (int sideLength) {
        super(sideLength, sideLength);
    }

}

public class ResizableRectangle extends Rectangle {

    public ResizableRectangle (int height, int width) {
        super(height, width);
    }

    public void setHeight (int height) { this.height = height; }
    public void setWidth (int width) { this.width = width; }

}

最後のクラス ResizableRectangle に注目してください。 「サイズ変更可能」を移動することにより、実際にモデルを改善しながら、サブクラスにコードを再利用します。これを次のように考えてください。正方形は正方形のままで自由にサイズ変更できませんが、正方形ではない長方形はサイズ変更できます。ただし、正方形は長方形であるため、すべての長方形をサイズ変更することはできません(「アイデンティティ」を保持したまま自由にサイズ変更することはできません)。 (o_O)したがって、サイズ変更できない基本 Rectangle クラスを作成するのは理にかなっています。これは some 長方形の追加のプロパティです。

2つの(簡単にするために)プロパティwidth、heightを持つクラスRectangleがあると仮定しましょう。これら2つのプロパティを変更できます:r.width = 1、r.height = 2。
ここで、正方形をis_a Rectangleと言います。しかし、クレームは「正方形は長方形のように振る舞います」正方形のオブジェクトに.width = 1および.height = 2を設定することはできません(高さを設定するとクラスが幅を調整する可能性があり、逆も同様です)。したがって、SquareタイプのオブジェクトがRectangleのように動作しないため、それらを(完全に)置換できない場合が少なくとも1つあります。

OOD / OOP技術は、ソフトウェアが実世界を表現できるようにするために存在すると考えています。現実の世界では、正方形は等しい辺を持つ長方形です。正方形は、正方形であると決定したからではなく、等しい辺を持つためだけの正方形です。したがって、OOプログラムはそれに対処する必要があります。もちろん、オブジェクトをインスタンス化するルーチンがオブジェクトを正方形にしたい場合、長さプロパティと幅プロパティを同じ量に指定できます。オブジェクトを使用するプログラムが後で正方形であるかどうかを知る必要がある場合、それを尋ねるだけです。オブジェクトには、“ Square”という読み取り専用のブール型プロパティを含めることができます。呼び出し元のルーチンがそれを呼び出すと、オブジェクトは返すことができます(長さ=幅)。これは、四角形オブジェクトが不変であっても当てはまります。さらに、四角形が実際に不変である場合、Squareプロパティの値をコンストラクターで設定し、それを使用して実行できます。なぜこれが問題なのですか? LSPでは、サブオブジェクトを適用するには不変である必要があり、四角形のサブオブジェクトである正方形は、違反の例としてよく使用されます。しかし、使用ルーチンがオブジェクトを“ objSquare”として呼び出す場合、その内部の詳細を知る必要があるため、これは良い設計ではないようです。長方形が正方形であるかどうかを気にしなくても良いと思いませんか?そして、それは長方形のメソッドが関係なく正しいからだろう。 LSPに違反した場合のより良い例はありますか?

もう1つの質問:オブジェクトはどのようにして不変になりますか? “ Immutable”はありますかインスタンス化時に設定できるプロパティ?

答えを見つけましたが、それは私が期待したものです。私はVB .NET開発者なので、それが私が興味を持っていることです。しかし、概念は言語間で同じです。 VB .NETでは、プロパティを読み取り専用にして不変クラスを作成し、Newコンストラクターを使用して、インスタンス化ルーチンがオブジェクトの作成時にプロパティ値を指定できるようにします。一部のプロパティに定数を使用することもできますが、それらは常に同じです。作成からオブジェクトは不変です。

問題は、説明されているものが実際には「タイプ」ではないことです。ただし、累積的な緊急プロパティです。

あなたが本当に持っているのは四辺形で、その両方が「正方形」です。および「長方形」は、角度と側面のプロパティから派生した単なるアーティファクトです。

「Square」の概念全体(または長方形でさえも)相互および問題のオブジェクトに関連するオブジェクトのプロパティのコレクションの単なる抽象表現であり、自身のオブジェクトのタイプではありません。

これは、「正方形」であるかどうかを決定するのはタイプではないため、タイプレス言語のコンテキストで問題を考えるのに役立ちます。しかし、「正方形」であるかどうかを決定するオブジェクトの実際のプロパティ。

抽象化をさらに進めたい場合は、四角形があるとは言いませんが、ポリゴンまたはシェイプさえあると思います。

非常に簡単です:)クラス(派生チェーンの最初)がより「基本」であるほど、最も一般的です。

形状の例->長方形->正方形。

ここで、正方形は(制約された寸法を持つ)長方形の特殊なケースであり、長方形は形状の特殊なケースです。

別の方法で言う-「は」を使用テスト。スクワイアは長方形です。しかし、長方形は必ずしも正方形ではありません。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top