[ 정보처리기사 ]
객체지향 설계 5대 원칙(SOLID)
히앤님
2025. 6. 25. 13:45
반응형
SMALL
SOLID는 객체지향 설계에서 유지보수성과 확장성을 높이기 위한 5가지 핵심 원칙이다.
로버트 마틴이 제안한 원칙이며 좋은 소프트웨어 설계를 위한 지침으로 널리 사용된다.
✅ 객체지향 설계 5대 원칙(SOLID)
약자 | 원칙 이름 | 의미 |
S | 단일 책임 원칙 (Single Responsibility Principle) | 클래스는 하나의 책임만 가져야 한다. => 한 사람은 한 가지 일만 하자! |
O | 개방-폐쇄 원칙 (Open/Closed Principle) | 확장에는 열려있고, 수정에는 닫혀 있어야 한다. => 새 기능은 더하고, 원래꺼는 건드리지 말자! |
L | 리스코프 치환 원칙 (Liskov Substitution Principle) | 자식 클래스는 부모 클래스와 호환되어야 한다. => 부모 대신 자식이 와도 똑같이 작동하게 하자! |
I | 인터페이스 분리 원칙 (Interface Segregation Principle) | 사용하지 않는 기능의 의존성은 분리해야 한다. => 꼭 필요한 기능만을 쓰자! |
D | 의존성 역전 원칙 (Dependency Inversion Principle) | 구체 클래스가 아니라 추상(인터페이스)에 의존해야 한다. => 이름이 아니라 역할로 연결하자! |
솔-개-리-인-의
"솔개리가 인터페이스를 의심했다"
- 솔 → S → 단일 책임 -> 이 클래스에 기능을 하나 더 넣어야 하는데… "단일 책임 원칙에 어긋나!"
- 개 → O → 개방-폐쇄 -> 기존 코드는 손대지 않고 새로운 기능을 추가만 할 수 있어야 함.
- 리 → L → 리스코프 -> 자식 클래스가 부모의 역할을 못 하면 리스코프 위반!
- 인 → I → 인터페이스 분리 -> 쓸모없는 함수들 억지로 구현해야 한다면? → 인터페이스 분리 위반.
- 의 → D → 의존 역전 -> "new 직접 쓰지 마! 추상화된 인터페이스를 써!"
1️⃣S - 단일 책임 원칙 (Single Responsibility Principle)
: 하나의 사람은 한 가지 일만 해야 한다.
-> 엄마는 요리만 하고, 아빠는 운전만 해요. 엄마가 운전하고 빨래하고 청소까지 하면 힘들겠죠?
// ❌ 여러 일 하는 로봇
class Robot {
void cook() { System.out.println("요리하기"); }
void drive() { System.out.println("운전하기"); }
}
// ✅ 일 나눠주기
class CookRobot {
void cook() { System.out.println("요리하기"); }
}
class DriveRobot {
void drive() { System.out.println("운전하기"); }
}
2️⃣ O - 개방/폐쇄 원칙 (Open/Closed Principle)
: 새로운 기능은 더해서 만들고, 기존 건 바꾸지 말자!
-> 새 게임 캐릭터를 추가하려고 할 때, 기존 캐릭터를 뜯어고치지 않아도 되는 게 좋아요!
// 인터페이스(약속)
interface Animal {
void sound();
}
// 기존 동물
class Dog implements Animal {
public void sound() { System.out.println("멍멍"); }
}
// 나중에 추가한 동물
class Cat implements Animal {
public void sound() { System.out.println("야옹"); }
}
// 바꾸지 않고도 추가 가능!
class Zoo {
void hear(Animal a) {
a.sound();
}
}
3️⃣L - 리스코프 치환 원칙 (Liskov Substitution Principle)
: 엄마 대신 아빠가 와도 똑같이 잘 작동해야 해요!
-> 자동차를 타야 하는데, 트럭이 와도 탈 수 있어야 해요. 근데 비행기가 오면? 안 되겠죠!
class Bird {
void fly() { System.out.println("난다!"); }
}
class Sparrow extends Bird {
void fly() { System.out.println("참새 난다!"); }
}
// ❌ 타조는 날 수 없는데 상속하면 문제 생김
class Ostrich extends Bird {
void fly() { throw new UnsupportedOperationException("타조는 못 날아!"); }
}
이렇게 되면 부모 클래스(Bird)를 쓸 수 있는 곳에 자식(Ostrich)을 넣으면 문제가 생겨요. → 원칙 위반!
4️⃣I - 인터페이스 분리 원칙 (Interface Segregation Principle)
: 필요한 것만 골라 쓰자!
-> 나는 게임기에서 달리기만 하고 싶어! 그런데 점프, 수영, 총쏘기도 다 해야 하면 귀찮아요.
// ❌ 너무 많은 기능
interface SuperHero {
void fly();
void swim();
void shoot();
}
// ✅ 나눠서 필요한 것만
interface Flyer { void fly(); }
interface Swimmer { void swim(); }
class Superman implements Flyer, Swimmer {
public void fly() { System.out.println("하늘 날기!"); }
public void swim() { System.out.println("헤엄치기!"); }
}
5️⃣ D - 의존성 역전 원칙 (Dependency Inversion Principle)
: 정확한 이름 말고 역할만 알려줘!
-> “게임기를 써요” → 닌텐도든 PS든 괜찮아요.
“닌텐도만 써요” → PS는 못 써요.
// 역할만 먼저 정해놓기
interface GameConsole {
void play();
}
// 실제 제품
class Nintendo implements GameConsole {
public void play() { System.out.println("닌텐도 게임!"); }
}
class Playstation implements GameConsole {
public void play() { System.out.println("플스 게임!"); }
}
// 사용하는 사람은 '역할'만 알면 됨
class Gamer {
GameConsole console;
Gamer(GameConsole console) {
this.console = console;
}
void startGame() {
console.play();
}
}
반응형
LIST