복잡한뇌구조마냥

[JAVA] 객체 지향 설계의 5대 원칙 – SOLID 본문

BE/JAVA

[JAVA] 객체 지향 설계의 5대 원칙 – SOLID

지금해냥 2025. 8. 10. 23:03

1. SOLID란?

SOLID는 로버트 C. 마틴(Robert C. Martin, Uncle Bob)이 정리한 객체 지향 설계 5대 원칙의 앞글자를 딴 용어입니다.

목표: 유지보수성, 확장성, 재사용성이 높은 코드 설계

 

약어 원칙 이름의미
S SRP: 단일 책임 원칙 한 클래스는 하나의 책임만 가져야 한다
O OCP: 개방-폐쇄 원칙 확장에는 열려 있고, 변경에는 닫혀 있어야 한다
L LSP: 리스코프 치환 원칙 하위 타입은 상위 타입을 대체할 수 있어야 한다
I ISP: 인터페이스 분리 원칙 사용하지 않는 메서드는 만들지 않는다
D DIP: 의존 역전 원칙 추상화에 의존하고, 구체화에 의존하지 않는다
 

 

2. SRP – 단일 책임 원칙 (Single Responsibility Principle)

정의

한 클래스는 오직 하나의 변경 이유만 가져야 한다.

  • 한 클래스가 여러 가지 역할을 하면, 한 부분의 변경이 다른 기능에 영향을 줄 수 있음.
  • 책임이 분리되어야 수정 범위가 작아지고 유지보수가 쉬워짐.

위반 예시

public class ReportManager {
    public void generateReport() { /* 보고서 생성 */ }
    public void printReport() { /* 보고서 출력 */ }
}
  • 보고서 생성과 출력이라는 두 책임이 하나의 클래스에 있음.

개선 예

public class ReportGenerator { public void generateReport() { /* ... */ } }
public class ReportPrinter { public void printReport() { /* ... */ } }

3. OCP – 개방-폐쇄 원칙 (Open-Closed Principle)

정의

확장에는 열려 있고, 변경에는 닫혀 있어야 한다.

  • 새로운 기능을 추가할 때 기존 코드를 수정하지 않고 확장할 수 있어야 함.

위반 예시

public class DiscountService {
    public double getDiscount(String type) {
        if (type.equals("VIP")) return 0.2;
        else if (type.equals("GOLD")) return 0.1;
        else return 0.0;
    }
}
  • 새로운 할인 정책 추가 시 if-else 수정 필요.

개선 예시 (다형성 활용)

interface DiscountPolicy { double getDiscount(); }

class VipDiscount implements DiscountPolicy { public double getDiscount() { return 0.2; } }
class GoldDiscount implements DiscountPolicy { public double getDiscount() { return 0.1; } }

public class DiscountService {
    public double apply(DiscountPolicy policy) { return policy.getDiscount(); }
}

4. LSP – 리스코프 치환 원칙 (Liskov Substitution Principle)

정의

하위 클래스는 상위 클래스의 행위를 변경하지 않고 대체 가능해야 한다.

  • 부모 클래스 객체가 사용되는 곳에 자식 클래스를 넣어도 정상 동작해야 함.
  • 계약(Contract) 위반 시 원칙 위반.

위반 예시

class Rectangle {
    protected int width, height;
    public void setWidth(int w) { this.width = w; }
    public void setHeight(int h) { this.height = h; }
}

class Square extends Rectangle {
    @Override
    public void setWidth(int w) {
        this.width = w; this.height = w; // 강제로 정사각형 유지
    }
}
  • Rectangle을 기대했는데 Square는 동작이 달라짐.

해결

  • 상속 대신 구성(Composition) 활용
  • 계약 위반 없이 공통 동작 재정의

5. ISP – 인터페이스 분리 원칙 (Interface Segregation Principle)

정의

클라이언트는 자신이 사용하지 않는 메서드에 의존하지 않아야 한다.

  • 너무 많은 메서드를 가진 “비대한” 인터페이스는 피해야 함.

위반 예시

interface Machine {
    void print();
    void scan();
    void fax();
}
class SimplePrinter implements Machine {
    public void print() { /* ok */ }
    public void scan() { throw new UnsupportedOperationException(); }
    public void fax() { throw new UnsupportedOperationException(); }
}

개선 예시

interface Printer { void print(); }
interface Scanner { void scan(); }

class SimplePrinter implements Printer { public void print() { /* ok */ } }

 


6. DIP – 의존 역전 원칙 (Dependency Inversion Principle)

정의

고수준 모듈은 저수준 모듈에 의존하지 않고, 추상화에 의존해야 한다.

  • 구현 클래스가 아닌 인터페이스/추상 클래스에 의존
  • 의존성 주입(DI) 패턴과 함께 사용

위반 예시

class MySQLRepository {
    public void save() { /* MySQL 저장 */ }
}

class UserService {
    private MySQLRepository repo = new MySQLRepository();
}
  • UserService가 MySQL에 종속됨 → DB 변경 어려움.

개선 예시

interface UserRepository { void save(); }

class MySQLRepository implements UserRepository {
    public void save() { /* MySQL 저장 */ }
}

class UserService {
    private final UserRepository repo;
    public UserService(UserRepository repo) { this.repo = repo; }
}

 


7. 마무리

SOLID 원칙은 코드 품질을 높이는 설계 지침입니다.
단, 원칙 준수에 집착하면 오히려 복잡성이 증가할 수 있으므로 필요한 곳에 적절히 적용하는 것이 중요합니다.

 

참고자료:

https://velog.io/@haero_kim/SOLID-%EC%9B%90%EC%B9%99-%EC%96%B4%EB%A0%B5%EC%A7%80-%EC%95%8A%EB%8B%A4

 

SOLID 원칙, 어렵지 않다!

객체지향 프로그래밍 설계 원칙에 대해 알아보기

velog.io

 

LIST