SOLID原則とは
SOLIDとは、オブジェクト指向設計の5つの基本的な原則を指す。
- S – 単一責任の原則 (Single Responsibility Principle: SRP)
- O – オープンクローズドの原則 (Open/Closed Principle: OCP)
- L – リスコフの置換原則 (Liskov Substitution Principle: LSP)
- I – インターフェース分離の原則 (Interface Segregation Principle: ISP)
- D – 依存関係逆転の原則 (Dependency Inversion Principle: DIP)
これらの原則は、Robert C. Martinによって提唱され、
- プログラムの可読性
- 再利用性
- 保守性
- の向上を目的としています。
の向上を目的としている。
単一責任の原則
一つのクラスは、一つの責任だけを持つべきという原則。
つまり、特定の責任に関連する変更を行う際に、その変更が他の部分に意図しない影響を及ぼす可能性が低くなるということだ。
NG:単一責任の原則を満たしていないコード
以下のコードは単一責任の原則を満たしていない。
なぜかというと、経理部と人事部で使われるロジックが1つのクラスに書かれているからだ。
仮に、経理部だけ労働時間を取得するロジック(get_working_timeメソッド)を修正したいとなった場合、人事部で使っているcalculate_salaryメソッドはバグってしまう。
class Employee attr_reader :name, :department def initialize(name, department) @name = name @department = department end # 経理部で使われるメソッド # 給与の計算をする def calculate_salary salary = get_working_time * 時給 puts "#{@name}の給与は#{salary}円です" end # 人事部で使われるメソッド # 労働時間を計算する def report_working_time puts "#{@name}の労働時間は#{get_working_time}です" end private def get_working_time # 労働時間の計算をするロジック end end
GOOD:単一責任の原則を満たしているコード
SalaryCalculator
クラスは給与の計算に関する責任を持ち、WorkingTimeReporter
クラスは労働時間の報告に関する責任を持つ。
これにより、各クラスが一つの責任だけを持つことになった。
class Employee attr_reader :name, :department def initialize(name, department) @name = name @department = department end end class SalaryCalculator def initialize(employee) @employee = employee end def calculate_salary salary = get_working_time * 時給 puts "#{@employee.name}の給与は#{salary}円です" end private def get_working_time # 人事部で使う労働時間の計算をするロジック end end class WorkingTimeReporter def initialize(employee) @employee = employee end def report_working_time puts "#{@employee.name}の労働時間は#{get_working_time}時間です" end private def get_working_time # 経理部で使う労働時間の計算をするロジック end end employee = Employee.new('kato', 'engineering') salary_calculator = SalaryCalculator.new(employee) working_time_reporter = WorkingTimeReporter.new(employee) salary_calculator.calculate_salary working_time_reporter.report_working_time
オープンクローズドの原則
クラスは拡張に対して開かれていて、変更に対して閉じているべき。
つまり、既存コードの変更なしに新しい機能や振る舞いを追加できるように設計すべきということ。
リスコフの置換原則
サブクラスは、スーパークラスと置換可能であるべき。
つまり、スーパークラスをサブクラスに置換したとしても、プログラムの振る舞いが正しく保たれるべきということ。
サブクラスをスーパークラスに置き換えてもプログラムが正常に動作することが期待されるため、コードの挙動が予測可能になり、バグの発生リスクを低減できる。
インターフェース分離の原則
クラスは不必要なインターフェースを持つべきではない。
つまり、クラスが実際に使用しないメソッドを実装する必要がないということを意味する。
最小限のインターフェースのみを持つことで、クラスの役割と責任が明確になり、システムの変更や拡張が容易になることがメリット。
依存関係逆転の原則
高レベルのモジュールは、低レベルのモジュールに依存すべきではなく、両方とも抽象に依存すべき。
具体的な実装ではなく、抽象に依存することで、モジュール間の結合度を低く保ち、再利用性や拡張性を向上させることができる