자바 디자인 패턴 용어 사전
원칙단일 책임 · 개방-폐쇄 · 의존 역전 · OCP

SOLID

객체지향 설계의 다섯 원칙. 대부분의 GoF 패턴이 이 원칙들을 구현한 결과물이다.

패턴의 토대가 되는 다섯 가지 설계 원칙.

S  단일 책임 (SRP)   클래스는 변경 이유가 하나여야 한다
O  개방-폐쇄 (OCP)   확장에는 열려 있고 수정에는 닫혀 있어야 한다
L  리스코프 치환(LSP) 하위 타입은 상위 타입을 대체할 수 있어야 한다
I  인터페이스 분리(ISP) 쓰지 않는 메서드에 의존하지 않게 잘게 나눈다
D  의존 역전 (DIP)   구체가 아니라 추상에 의존한다

SRP — "변경 이유"가 기준이다

// ❌ 이 클래스는 세 가지 이유로 바뀐다
class Report {
    String generate() { ... }      // 내용 규칙이 바뀌면
    void saveToFile() { ... }      // 저장 방식이 바뀌면
    void sendEmail() { ... }       // 발송 방식이 바뀌면
}

"하나만 한다"가 아니라 "바뀔 이유가 하나다" 가 정확한 기준이다.

OCP — 새 기능을 추가할 때 기존 코드를 안 고친다

// ❌ 결제 수단이 늘 때마다 이 메서드를 고쳐야 한다
void pay(String type) {
    if (type.equals("card")) { ... }
    else if (type.equals("bank")) { ... }
}

// ✅ 인터페이스를 두면 새 구현을 '추가' 하기만 하면 된다
interface PayMethod { void pay(long amount); }
void pay(PayMethod m, long amount) { m.pay(amount); }

Strategy 패턴이 곧 OCP의 구현이다. 대부분의 GoF 패턴이 이 원칙을 다른 상황에 적용한 것이다.

DIP — 화살표를 뒤집는다

❌ 서비스 → MySqlRepository (고수준이 저수준에 의존) ✅ 서비스 → Repository(인터페이스) ← MySqlRepository

  • (저수준이 추상에 의존)

인터페이스를 '고수준 쪽' 이 소유하는 것이 핵심이다

GoF의 두 가지 대원칙

  • ① 구현이 아니라 인터페이스에 프로그래밍하라
  • ② 상속보다 합성을 선호하라

상속은 컴파일 시점에 고정되고 캡슐화를 깬다(부모 구현에 의존) 합성은 런타임에 바꿔 끼울 수 있다

원칙은 목적이 아니다

  • 원칙을 지키려고 인터페이스를 남발하면 구현이 하나뿐인 추상이 쌓인다
  • 실제로 바뀌는 축을 찾아 그곳만 유연하게 두는 것이 요령이다
  • "지금 바뀌지 않는 것" 을 추상화하면 순수한 비용이다 (YAGNI)

면접 함정

  • "SRP는 클래스를 작게 만드는 것" → 크기가 아니라 변경 이유의 수다.
  • "인터페이스를 많이 만들면 좋은 설계" → 구현이 하나뿐인 인터페이스는 대개 불필요한 간접층이다.

LSP를 어기는 전형적 예

class Rectangle {
    void setWidth(int w) { this.w = w; }
    void setHeight(int h) { this.h = h; }
    int area() { return w * h; }
}

class Square extends Rectangle {          // "정사각형은 직사각형이다" — 수학적으로는 맞다
    void setWidth(int w) { this.w = this.h = w; }   // 높이까지 바꿔야 한다
    void setHeight(int h) { this.w = this.h = h; }
}
void test(Rectangle r) {
    r.setWidth(5); r.setHeight(4);
    assert r.area() == 20;      // Square 를 넘기면 16 이 나온다 → 깨진다
}

"is-a 관계"만으로는 부족하다 — 하위 타입은 상위의 계약까지 지켜야 한다. 이 예가 상속을 남용하면 안 되는 이유의 교과서다.

ISP — 뚱뚱한 인터페이스를 쪼갠다

// ❌ 프린터만 만드는 사람도 팩스·스캔을 구현해야 한다
interface Machine { void print(); void fax(); void scan(); }

// ✅ 필요한 것만 조합한다
interface Printer { void print(); }
interface Scanner { void scan(); }
class SimplePrinter implements Printer { }

원칙 사이의 긴장

SRP 를 극단으로 밀면 클래스가 폭발한다 OCP 를 극단으로 밀면 추상이 폭발한다

원칙은 서로 긴장 관계에 있고, 균형점은 '무엇이 실제로 바뀌는가' 가 정한다 바뀌지 않는 축을 유연하게 만드는 것은 순수한 낭비다

함께 보면 좋은 용어

노트에서 맥락과 함께 보기 — 원칙 — 패턴이 서 있는 바닥