リスコフの置換原則の探求

SOLIDという用語は、ソフトウェアアーキテクチャの5つの原則のセットを指すために使用される一般的な頭字語です。これらには、SRP(単一責任)、オープン/クローズ、リスコフの置換、インターフェイス分離、および依存性逆転が含まれます。

LSP(Liskov Substitution Principle)は、OOPの基本原則であり、派生クラスは、動作を変更せずに基本クラスを拡張できる必要があると述べています。言い換えると、派生クラスは基本タイプを置き換えることができる必要があります。つまり、基本クラスへの参照は、動作に影響を与えることなく派生クラスに置き換えることができます。リスコフの置換原則は、強力な振る舞いサブタイピングを表しており、1987年にバーバラリスコフによって導入されました。

バーバラ・リスコフによれば、「ここで必要なのは、次の置換プロパティのようなものです。タイプSの各オブジェクトo1に対して、タイプTのオブジェクトo2があり、すべてのプログラムPに対してTで定義されている場合、Pの動作o1がo2の代わりに使用される場合、SはTのサブタイプです。」

リスコフの置換原則の違反の典型的な例は、長方形-正方形の問題です。Squareクラスは、Rectangleクラスを拡張し、幅と高さが等しいことを前提としています。

次のクラスを考えてみましょう。Rectangleクラスには、幅と高さの2つのデータメンバーが含まれています。高さ、幅、面積の3つのプロパティもあります。最初の2つのプロパティは長方形の高さと幅を設定しますが、Areaプロパティには長方形の面積を返すゲッターがあります。

 class Rectangle

    {

        protected int width;

        protected int height;

         public virtual int Width

        {

            get

            {

                return width;

            }

            set

            {

                width = value;

            }

        }

 

        public virtual int Height

        {

            get

            {

                return height;

            }

            set

            {

                height = value;

            }

        }

               

       public int Area

        {

            get

            {

                return height * width;

            }

         }    

    }

正方形は、すべての辺が同じサイズである、つまり正方形の幅と高さが同じである長方形の一種です。

class Square : Rectangle

    {

        public override int Width

        {

            get

            {

                return width;

            }

            set

            {

                width = value;

                height = value;

            }

        }

        public override int Height

        {

            get

            {

                return width;

            }

            set

            {

                width = value;

                height = value;

            }

        }

    }

 ObjectFactoryと呼ばれる別のクラスについて考えてみます。

 class ObjectFactory

    {

        public static Rectangle GetRectangleInstance()

        {

            return new Square();

        }

    }

SquareクラスのWidthプロパティとHeightプロパティのセッターは、高さと幅が同じになるようにオーバーライドおよび変更されていることに注意してください。次に、heightプロパティとwidthプロパティを使用して、Rectangleクラスのインスタンスを作成して設定します。

Rectangle s = ObjectFactory.GetRectangleInstance();

s.Height = 9;

s.Width = 8;

Console.WriteLine(s.Area);

上記のコードスニペットを実行すると、コンソールに値64が表示されます。上記の幅と高さはそれぞれ9と8であるため、期待値は72です。これは、リスコフの置換原則の違反です。これは、Rectangleクラスを拡張したSquareクラスが動作を変更したためです。リスコフの置換原則に違反しないようにするために、SquareクラスはRectangleクラスを拡張できますが、動作を変更しないでください。プロパティWidthとHeightの両方のセッターを変更することにより、動作が変更されました。正方形の場合、高さと幅の値は同じです。長方形の場合、同じであってはなりません。

これをどのように修正しますか、つまり、この原則に違反しないようにしますか?さて、Quadrilateralと呼ばれる新しいクラスを導入して、RectangleクラスとSquareクラスの両方がQuadrilateralクラスを拡張するようにすることができます。

 public class Quadrilateral

    {

        public virtual int Height { get; set; }

        public virtual int Width { get; set; }

        public int Area

        {

            get

            {

                return Height * Width;

            }

        }

    } 

これで、RectangleクラスとSquareクラスの両方がQuadrilateralクラスを拡張し、WidthプロパティとHeightプロパティの値を適切に設定する必要があります。本質的に、派生クラスには、面積を計算する必要がある四角形インスタンスのタイプに基づいて、これらのプロパティに値を設定するために必要な機能が必要です。四辺形クラスでは、HeightプロパティとWidthプロパティの両方が仮想としてマークされていることに注意してください。つまり、これらのプロパティは、四辺形クラスを派生させるクラスによってオーバーライドされる必要があります。

Liskov Substitution Principleは、Open Close Principleの拡張であり、「実装されていない例外」をスローするコードを記述した場合、または基本クラスで仮想としてマークされた派生クラスのメソッドを非表示にした場合に違反します。コードがリスコフの置換原則に準拠している場合、多くの利点があります。これらには、コードの再利用性、結合の削減、およびメンテナンスの容易さが含まれます。