Lumen

Lumen

Eager to know more, about the world, about the intelligence, and about myself.
github

合成は継承に勝る

なぜ「継承よりも構成を優先する」べきなのか?#

最近の投稿で、私はプロジェクトのコードベースの複雑さに対する不満を共有しました。基本的に、それはあまりにも複雑で絡み合っています。私の不快感にもかかわらず、私は解決策を見つける必要があり、それがデザインパターンに導きました。

私が何度も耳にした原則の一つは「継承よりも構成を優先する」です。最初は、両者の違いについて漠然とした理解しか持っていませんでしたし、この概念をプロジェクトにどのように実装するかもわかりませんでした。しかし、この ArjanCodes のビデオが私にその理由を理解させてくれました。今からそれを説明します。

結合が複雑さを生む#

プロジェクトを設計する際、特にオブジェクト指向プログラミングでは、異なるオブジェクト間の相互作用や依存関係により、複雑さが急速に増大する可能性があります。この複雑さは結合から生じます。

複雑な結合は、いくつかの問題を引き起こす可能性があります。異なるオブジェクト間の複雑な相互作用を考慮しなければならないため、新機能の修正や追加が困難になります。変更はコードベース全体に予期しない結果をもたらす可能性があります。さらに、高度に結合されたコードでは、十分なカバレッジを達成するためにすべてのシナリオをテストする必要があるため、単体テストがより困難になります。

以下の図は、システム結合の異なるレベルを示しています。高度に結合されたシステムでは、すべての可能な入力の組み合わせをテストする必要があります。しかし、計算をステップに分解することで、各関数は単一の入力とその対応する出力を検証することで確認でき、テストがはるかに容易になります。

Mermaid Loading...
結合の異なるレベルの比較

複雑な継承構造が結合を引き起こす#

Arjan の例から引き出すと、純粋な継承ベースのアプローチでは、Employeeクラスが従業員に関連するすべてのアクション(ID、年齢、性別、支払い方法など)をカプセル化するかもしれません。各従業員タイプに対して、基本クラスから派生したサブクラスを作成します。このアプローチは、継承を通じて問題を解決します。

しかし、すべての責任を単一のEmployeeクラスに割り当てると、成長するプロジェクトとその進化するニーズは、最終的に広がる階層ツリーをもたらします。各部分は親に依存しており、同じ親を共有する子クラス間に間接的な結合を生み出します。基本クラスのいずれかを変更すると混乱が生じる可能性があります。新しいバリアントが既存の実装からわずかに互換性のない要件を持っている場合、非常に基本的なクラスから継承し、すべての機能を再実装しなければならないかもしれません。要するに、継承は結合を生み出し、それを過剰に使用すると作業が複雑になるのです。

Mermaid Loading...
複雑な継承ツリー

インターフェースを優先する#

問題は、複雑なシステムを作成すべきでないと言っているのではなく、むしろこれらのシステム内でコンポーネントの論理的な分離を確保することです。前の例を検討すると、Employeeクラスは複数の責任が割り当てられているため問題があります。異なる従業員タイプを細分化し、さまざまな支払いと手数料を管理しており、これらは別々のインスタンスによって処理されるべきです

これに対処するために、異なる契約タイプのためのContractクラスと、さまざまな手数料のためのCommissionクラスを作成できます。これらのインスタンスは、Employeeクラスに渡すことができます。これらが統一されたインターフェースを維持する限り、私たちの作業ははるかに簡単になります。

Mermaid Loading...
これの方がずっと良いですね?

結論#

デザインパターンは私にとってかなり新しいものですが、彼らが目指していることはなんとなく理解できます。それは、システムの複雑さを下げ、可能であればモジュール化することです。

「継承よりも構成を優先する」という考え方は、抽象的なレベルでの依存性注入に非常に似ています。これらはすべて、ローカルな単純さを分離し保持するという同じ目標を表現する異なる用語であり、それによってコードの保守性と柔軟性を向上させます。

参考文献#

なぜ構成が継承よりも優れているのか - 詳細な Python の例

Python における依存性逆転と依存性注入

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。