[객체지향] SOLID 원칙 (1/2)

SOLID 원칙

- 객체 지향 프로그래밍에서 좋은 설계와 유지보수 가능한 소프트웨어를 만들기 위한 다섯 가지 핵심 원칙을 제공한다.

- 소프트웨어 개발 과정에서 코드의 유연성, 재사용성, 유지보수성을 높이는 데 중요한 역할을 한다.

- SOLID는 각 원칙의 첫 글자를 따서 명명된 약어이다.

SRP (Single Responsibility Principle, 단일 책임 원칙)

https://medium.com/p/ad3ae3e264bb

정의

- 클래스는 오직 하나의 책임만 가져야하며, 그 책임을 완전히 캡슐화해야 한다는 원칙이다.

목표

- 클래스를 설계할 때 각 클래스가 하나의 역할만 수행하도록 하여, 클래스의 변경이 다른 클래스에 영향을 미치지 않도록 한다.

예시

[ SRP 적용 전 ] 

public class Employee {
    private String name;
    private double salary;

    // Employee 정보와 관련된 메서드
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    
    // 급여와 관련된 메서드
    public double getSalary() { return salary; }
    public void setSalary(double salary) { this.salary = salary; }
}

[ SRP 적용 후 ] 

public class Employee {
    private String name;

    // Employee 정보와 관련된 메서드
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}

public class Salary {
    private double salary;
    
    // 급여와 관련된 메서드
    public double getSalary() { return salary; }
    public void setSalary(double salary) { this.salary = salary; }
}

OCP (Open-Closed Principle, 개방-폐쇄 원칙)

정의

- 소프트웨어 엔티티(클래스, 모듈, 함수 등)는 확장에 대해서는 열려 있어야하고, 변경에 대해서는 닫혀 있어야 한다는 원칙이다.

목표

- 기존 코드를 변경하지 않고도 기능을 확장할 수 있도록 설계하여, 변경의 영향을 최소화한다.

예시

public abstract class Shape {
    public abstract double area();
}

public class Rectangle extends Shape {
    private double width;
    private double height;
    
    @Override
    public double area() { return width * height; }
}

public class Circle extends Shape {
    private double radius;
    
    @Override
    public double area() { return Math.PI * radius * radius; }
}

LSP (Liskov Substitution Principle, 리스코프 치환 원칙)

정의

- 자식 클래스는 부모 클래스의 역할을 대신할 수 있어야 하며, 자식 클래스를 부모 클래스로 교체해도 프로그램의 정확성이 유지되어야 한다는 원칙이다.

목표

- 상속받은 클래스가 부모 클래스의 계약을 준수하여, 코드의 신뢰성을 높이고 예상치 못한 버그를 방지한다.

- 상속받은 클래스는 부모 클래스와 동일한 동작을 해야 재활용 가능성이 높아진다. 

LSP 사용으로 발생할 수 있는 단점과 보완 방법

단점

- 상속 시 오버라이드를 한 것과 아닌 것의 혼란이 발생한다. 

- 상속 오버라이드를 잘못하면 로직 충돌이 발생한다.

- 기능을 너무 확장하거나 변경하면 재활용성이 낮아진다.

보완 방법

- 상속을 위한 설계를 한 클래스만 상속한다.

- 부모 클래스 상속 대신 인터페이스를 활용한다.

- 피할 수 없다면 상속을 하지만 부모와 상호 치환이 가능하도록 한다. 즉, 부모 클래스와 동일한 기능을 제공한다.

예시

public class Bird {
    public void fly() { /* fly logic */ }
}

public class Sparrow extends Bird {
    // fly() 메서드를 구현
}

public class Penguin extends Bird {
    @Override
    public void fly() {
        throw new UnsupportedOperationException("Penguins can't fly!");
    }
}

⊙ 참고 문헌

    1. 양세열, 「백엔드 취업 파트타임 스쿨 5기:Part 07. 스프링 프레임워크-Chapter 02. OOP와 스프링 프레임워크-03. OOP잘하는방법SOLID-001」, 제로베이스, 2024, https://zero-base.co.kr/
    2. 양세열, 「백엔드 취업 파트타임 스쿨 5기:Part 07. 스프링 프레임워크-Chapter 02. OOP와 스프링 프레임워크-03. OOP잘하는방법SOLID-002」, 제로베이스, 2024, https://zero-base.co.kr/
    3. 양세열, 「백엔드 취업 파트타임 스쿨 5기:Part 07. 스프링 프레임워크-Chapter 02. OOP와 스프링 프레임워크-03. OOP잘하는방법SOLID-003」, 제로베이스, 2024, https://zero-base.co.kr/
    4. ChatGPT, "SOLID 원칙"에 대한 답변, 2024년 09월 17일, https://chatgpt.com/
    5. Vlad Ungureanu, Single Responsibility Principle, Jul 8, 2019, https://medium.com/@learnstuff.io/single-responsibility-principle-ad3ae3e264bb
    6. Vlad Ungureanu, Open/Close Principle, Jul 22, 2019, https://medium.com/@learnstuff.io/open-close-principle-442ebafb3528
    7. Vlad Ungureanu, Liskov Substitution Principle, Aug 26, 2019, https://medium.com/@learnstuff.io/liskov-substitution-principle-ad0d6a51ffb0