密結合
8-2

必要なデータは引数で渡す

他クラスの計算を使い回したいとき、継承して super() 経由で呼ぶと、親クラスの内部実装という「暗黙の経路」に依存してしまう。親がメソッドの呼び合い方を変えただけでサブクラスの計算が狂う。必要な計算オブジェクトはコンストラクタや引数で明示的に渡し、委譲(コンポジション)で使う。

出張旅費の深夜割増計算

Bad

基本運賃クラスを継承し、super() の戻り値に割増を上乗せ。親の内部構造に縛られる

継承で計算を使い回す
class TravelFare:
    def one_way(self, km: int) -> int:
        return km * 20

    def round_trip(self, km: int) -> int:
        return km * 38  # 往復は割安レート


class LateNightTravelFare(TravelFare):
    def one_way(self, km: int) -> int:
        return super().one_way(km) + 200  # 深夜割増

    def round_trip(self, km: int) -> int:
        return super().round_trip(km) + 400
Good

基本運賃の計算機をコンストラクタ引数で受け取り、委譲して使う

コンポジション+引数渡し
class LateNightTravelFare:
    def __init__(self, base: TravelFare) -> None:
        self._base = base  # 必要な計算機は引数で明示的に受け取る

    def one_way(self, km: int) -> int:
        return self._base.one_way(km) + 200

    def round_trip(self, km: int) -> int:
        return self._base.round_trip(km) + 400

Bad 版は、親が round_trip() の内部を「one_way() を2回呼ぶ」実装に変えた瞬間、オーバーライドした one_way() の割増が二重加算される。委譲なら親の内部がどう変わっても、受け取った結果に割増を足すだけなので壊れない。

参考: 『良いコード/悪いコードで学ぶ設計入門』(ミノ駆動 著、技術評論社)第8章。コード例は原則を自分の題材で表現し直したオリジナル。
8-2

必要なデータは引数で渡す

他クラスの計算を使い回したいとき、継承して super() 経由で呼ぶと、親クラスの内部実装という「暗黙の経路」に依存してしまう。親がメソッドの呼び合い方を変えただけでサブクラスの計算が狂う。必要な計算オブジェクトはコンストラクタや引数で明示的に渡し、委譲(コンポジション)で使う。

出張旅費の深夜割増計算

Bad

基本運賃クラスを継承し、super() の戻り値に割増を上乗せ。親の内部構造に縛られる

継承で計算を使い回す
class TravelFare:
    def one_way(self, km: int) -> int:
        return km * 20

    def round_trip(self, km: int) -> int:
        return km * 38  # 往復は割安レート


class LateNightTravelFare(TravelFare):
    def one_way(self, km: int) -> int:
        return super().one_way(km) + 200  # 深夜割増

    def round_trip(self, km: int) -> int:
        return super().round_trip(km) + 400
Good

基本運賃の計算機をコンストラクタ引数で受け取り、委譲して使う

コンポジション+引数渡し
class LateNightTravelFare:
    def __init__(self, base: TravelFare) -> None:
        self._base = base  # 必要な計算機は引数で明示的に受け取る

    def one_way(self, km: int) -> int:
        return self._base.one_way(km) + 200

    def round_trip(self, km: int) -> int:
        return self._base.round_trip(km) + 400

Bad 版は、親が round_trip() の内部を「one_way() を2回呼ぶ」実装に変えた瞬間、オーバーライドした one_way() の割増が二重加算される。委譲なら親の内部がどう変わっても、受け取った結果に割増を足すだけなので壊れない。

参考: 『良いコード/悪いコードで学ぶ設計入門』(ミノ駆動 著、技術評論社)第8章。コード例は原則を自分の題材で表現し直したオリジナル。