Python基礎 オブジェクト指向SOLID(リスコフの置換原則)
| 登録日 | :2025/09/17 06:12 |
|---|---|
| カテゴリ | :Python基礎 |
L: Liskov Subsituation(リスコフの置換原則)
リスコフの置換原則
サブタイプは、そのスーパータイプと置換可能でなければならない。
サブタイプ:スーパークラスを継承したクラス
スーパータイプ:継承元となるクラス
正しい継承 = 「Is-a関係」+「振る舞いの同等性」
原則に違反した場合
-
利用者が想定しない挙動によるバグが発生する可能性が高まる
利用者はスーパータイプとサブタイプで同じ挙動を期待する。
挙動が異なると、サブタイプまで全て理解する必要がある -
リスコフの置換原則に違反したコードを使うと、オープンクローズドの原則に違反する可能性が高まる
利用側でクラスを判定するための分岐を入れるのはNG
(発展)契約による設計
プログラムコードの中にプログラムが満たすべき仕様について記述することで、正確で頑強なソフトウェアとする設計技法
-
事前条件
メソッド開始時に保証されるべき条件
メソッドの引数、メソッド開始時のインスタンスの状態 -
事後条件
メソッド正常終了時に保証されるべき条件
メソッド正常終了時にインスタンスの状態、クライアントに返す戻り値
サブタイプの事前条件はスーパータイプと同じかそれより弱い条件と置き換え、
(スーパータイプの事前条件は、サブタイプ側で全て許容する必要がある、もっとゆるい条件とする)
事後条件はスーパータイプと同じかそれより強い条件と置き換える
(スーパータイプの事後条件も同じく、サブタイプでは全て網羅する必要がある。つまりゆるくしたらダメ)
サンプルコード
from abc import ABCMeta, abstractmethod
class IShape(metaclass=ABCMeta):
@abstractmethod
def get_area(self) -> int:
pass
class Rectangle(IShape):
def __init__(self, _height: int = 0, _width: int = 0):
self.__height = _height
self.__width = _width
@property
def width(self) -> int:
return self.__width
@width.setter
def width(self, _width: int):
self.__width = _width
@property
def height(self) -> int:
return self.__height
@height.setter
def height(self, _height):
self.__height = _height
def get_area(self) -> int:
return self.__height * self.__width
class Square(IShape):
def __init__(self, _length: int = 0):
self.__length = _length
@property
def length(self) -> int:
return self.__length
@length.setter
def length(self, _length: int):
self.__length = _length
def get_area(self) -> int:
return self.__length ** 2
def f(shape: IShape):
print(shape.get_area())
if __name__ == '__main__':
r = Rectangle(3, 4)
f(r)
s = Square(3)
f(s)