🕌

【SOLID原則】オブジェクト指向設計の5つの基本原則まとめ

2024/08/11に公開

はじめに

SOLID原則は、オブジェクト指向プログラミングとソフトウェア設計の5つの基本原則を指す頭字語です。これらの原則は、ソフトウェアの保守性、拡張性、理解のしやすさを向上させることを目的としています。
今回はSOLID原則に関してのまとめ記事を書いていきます。

参考

Clean Architecture 達人に学ぶソフトウェアの構造と設計

https://medium.com/backticks-tildes/the-s-o-l-i-d-principles-in-pictures-b34ce2f1e898

SOLID原則について

SOLID原則は以下の5つの原則から成り立っています:

  • 単一責任の原則 (Single Responsibility)
  • オープン・クローズドの原則 (Open-Closed)
  • リスコフの置換原則 (Liskov Substitution)
  • インターフェース分離の原則 (Interface Segregation)
  • 依存性逆転の原則 (Dependency Inversion)

これらの原則を適切に適用することで、より柔軟で、保守しやすく、拡張性の高いソフトウェアを設計することができます。

1.単一責任の原則

単一責任の原則は、「クラスは単一の責任のみを持つべきである」という考え方です。

概要

この原則の核心は、ソフトウェアの構成要素の責任を明確に分離することにあります。

適用しない場合の問題点:

コードの複雑性の増大: 一つのクラスが多くの責任を持つことで、クラスが肥大化し、理解や保守が困難になる。
変更の影響範囲の拡大: 一つの変更が複数の機能に影響を与える可能性が高くなり、予期せぬバグを引き起こす。
テストの困難性: 多くの責任を持つクラスは、ユニットテストの作成が複雑になり、テストカバレッジの確保が困難になる。
再利用性の低下: 特定の機能だけを再利用したい場合でも、他の関連しない機能も含めて使用せざるを得なくなる。

適用することの利点:

コードの可読性向上: 各クラスの責任が明確になり、コードの理解が容易になる。
保守性の向上: 特定の機能の変更が他の機能に影響を与えにくくなり、バグの修正や機能の追加が容易になる。
テストの容易さ: 各クラスの責任が限定されるため、ユニットテストの作成と維持が簡単になる。
再利用性の向上: 単一の責任を持つクラスは、他のプロジェクトや異なるコンテキストでの再利用が容易になる。

2.オープン・クローズドの原則

オープン・クローズドの原則は、1988年にBertrand Mayerが提唱した「ソフトウェアの構成要素は拡張に対して開いていて、修正に対して閉じていなければならない」という原則です。

概要

ソフトウェアの振る舞いは、既存の成果物を変更せず、拡張できるようにすべきであるということです。もし、ちょっとした拡張のために、大量の書き換えが必要になるならそのソフトウェアシステムのアーキテクトは大失敗への道を進んでいることになります。

適用しない場合の問題点:

既存コードの頻繁な修正: 新機能の追加や変更のたびに既存のコードを修正する必要があり、リグレッションのリスクが高まる。
コードの不安定性: 頻繁な修正により、システム全体の安定性が損なわれ、予期せぬ副作用が発生する可能性が高くなる。
テストの再実行と更新: 既存コードの変更のたびに、関連するテストを更新し再実行する必要がある。
拡張の困難性: 新しい要件や機能を追加する際に、既存のコード構造が制約となり、実装が複雑化する。

適用することの利点:

拡張性の向上: 新機能の追加が既存のコードを変更せずに行えるため、システムの拡張が容易になる。
リグレッションリスクの低減: 既存の機能に影響を与えずに新機能を追加できるため、予期せぬバグの発生リスクが低下する。
並行開発の促進: 異なる機能や拡張を同時に開発できるため、開発効率が向上する。
テストの安定性: 既存の機能に対するテストを変更する必要がないため、テストスイートの安定性が保たれる。

3.リスコフの置換原則

リスコフの置換原則は、「プログラムの中で、サブタイプは常にそのベースタイプと置換可能でなければならない」という原則です。

概要

サブクラスは、そのスーパークラスの振る舞いを変更することなく、スーパークラスの代わりに使用できるべきだという考え方です。
子クラスは、親クラスと同じリクエストを処理して同じ結果を返すことができる必要があります。または、同じタイプの結果を返すこともできます。
子クラスが親クラスと同じアクションを実行できない場合、バグが発生する可能性があります。

適用しない場合の問題点:

予期せぬ動作: サブクラスがスーパークラスの契約を破ることで、システムの他の部分で予期せぬ動作やエラーが発生する。
型チェックの増加: サブクラスの特殊な振る舞いを処理するために、頻繁な型チェックやインスタンスの確認が必要になる。
コードの再利用性の低下: サブクラスがスーパークラスの代わりに使用できないため、ポリモーフィズムの利点を活かせない。
設計の一貫性の欠如: 継承関係にあるクラス間で一貫性のない振る舞いが生じ、システムの全体的な設計が複雑になる。

適用することの利点:

ポリモーフィズムの効果的な活用: サブクラスをスーパークラスの代わりに使用できるため、柔軟なコード設計が可能になる。
コードの予測可能性: クラス階層全体で一貫した振る舞いが保証され、システムの動作が予測しやすくなる。
テストの簡素化: スーパークラスのテストケースをサブクラスにも適用できるため、テスト工程が効率化される。
設計の堅牢性: 継承関係が適切に設計され、システム全体の一貫性が向上する。

4.インターフェース分離の原則

インターフェース分離の原則は、「クライアントは、自分が使用しないメソッドに依存させられるべきではない」という原則です。

概要

この原則は、大きな汎用的なインターフェースよりも、小さくて具体的なインターフェースを多く作ることを推奨します。

適用しない場合の問題点:

不要なメソッドの実装: クライアントが使用しないメソッドも実装する必要が生じ、コードの複雑性が増す。
依存関係の増加: 大きなインターフェースに依存することで、不必要な依存関係が生まれ、結合度が高くなる。
変更の影響範囲の拡大: 大きなインターフェースの変更が、それを実装するすべてのクラスに影響を与える。
テストの複雑化: 使用しないメソッドのモックやスタブも作成する必要が生じ、テストが複雑になる。

適用することの利点:

インターフェースの最適化: クライアントに必要な機能のみを提供することで、インターフェースがシンプルで焦点が絞られたものになる。
柔軟性の向上: 小さく特化したインターフェースを組み合わせることで、より柔軟なシステム設計が可能になる。
実装の容易さ: 必要な機能のみを実装すればよいため、クラスの実装が簡素化される。
テストの効率化: モックオブジェクトの作成が簡単になり、テストの記述と保守が容易になる。

5.依存性逆転の原則

依存性逆転の原則は、「上位レベルのモジュールは下位レベルのモジュールに依存すべきではない。両方とも抽象に依存すべきである」という原則です。

概要

この原則は、システムの結合度を低くし、柔軟性と再利用性を高めることを目的としています。変化しやすい具象への依存を避け、安定した抽象インターフェースに依存すべきであるという考え方です。

参照
https://ja.wikipedia.org/wiki/依存性逆転の原則

依存性逆転原則は以下二点を提唱している

  1. 上位モジュールはいかなるものも下位モジュールから持ち込んではならない。双方とも抽象(例としてインターフェース)に依存するべきである。
  2. 抽象は詳細に依存してはならない。詳細(具象的な実装内容)が抽象に依存するべきである。

適用しない場合の問題点:

高レベルモジュールと低レベルモジュールの強結合: 変更の影響が広範囲に及び、システムの柔軟性が低下する。
テストの困難性: 具体的な実装に依存することで、ユニットテストでのモックオブジェクトの使用が困難になる。
再利用性の低下: 特定の実装に強く依存するため、他のコンテキストでの再利用が難しくなる。
並行開発の制約: 高レベルモジュールと低レベルモジュールの開発が密接に結びつき、並行開発や独立した開発が困難になる。

適用することの利点:

モジュール間の疎結合: 高レベルモジュールと低レベルモジュールが抽象に依存することで、システムの柔軟性が向上する。
テストの容易さ: 依存関係を抽象化することで、モックオブジェクトを使用したユニットテストが容易になる。
再利用性の向上: 具体的な実装ではなく抽象に依存することで、コンポーネントの再利用性が高まる。
並行開発の促進: 高レベルモジュールと低レベルモジュールを独立して開発できるため、開発効率が向上する。

6.SOLID原則の利点

SOLID原則を適用することで、以下のような利点が得られます。

利点

  • 保守性の向上: 各原則を適用することで、コードの構造が改善され、変更や拡張が容易になります。
  • 再利用性の向上: 単一責任の原則やインターフェース分離の原則により、コンポーネントの再利用が容易になります。
  • テスト容易性の向上: 依存性の低減や責任の分離により、ユニットテストが書きやすくなります。
  • 柔軟性の向上: オープン・クローズドの原則や依存性逆転の原則により、システムの柔軟性が高まります。
  • 理解のしやすさの向上: 各コンポーネントの責任が明確になり、コードの理解が容易になります。
  • バグの減少: 適切に原則を適用することで、予期せぬ副作用やバグの発生リスクが低減します。
  • 開発効率の向上: 長期的には、これらの利点により開発効率が向上します。

7.SOLID原則の適用における注意点

SOLID原則は強力なガイドラインですが、過度に適用すると問題が生じる可能性があります。

注意点

  • 過度の抽象化を避ける: 必要以上に抽象化すると、かえってコードが複雑になる可能性があります。
  • コンテキストを考慮する: プロジェクトの規模や要件に応じて、適切なレベルで原則を適用する必要があります。
  • パフォーマンスとのバランス: 原則の適用がパフォーマンスに悪影響を与える可能性がある場合は、トレードオフを慎重に検討する必要があります。
  • 過度の分割を避ける: 単一責任の原則を極端に適用すると、過度に細かいクラスが生まれる可能性があります。
  • チームの理解度を考慮する: チームメンバーの経験レベルや理解度に応じて、適切なレベルで原則を適用することが重要です。
  • 既存のコードベースとの整合性: 既存のプロジェクトに原則を適用する際は、既存のアーキテクチャやデザインパターンとの整合性を考慮する必要があります。

まとめ

5つの原則についてまとめました。日々のコードを書く時に意識して記載してよりわかりやすく、保守性の高いコードを目指していきたいですね。

Discussion