1. 단일 책임 원칙 (SRP: Single Responsibility Principle)
하나의 클래스는 하나의 책임만 가져야 한다.
위반한 코드
class UserService {
public void registerUser(String username) {
// 회원 가입 로직
}
public void sendEmail(String message) {
// 이메일 발송 로직 (책임 2개!)
}
}
Java
복사
이 클래스는 회원가입 + 이메일 발송 두 가지 책임을 가진다. 수정 시 영향 범위가 커짐.
올바른 코드
class UserService {
public void registerUser(String username) {
// 회원 가입 로직
}
}
class EmailService {
public void sendEmail(String message) {
// 이메일 발송 로직
}
}
Java
복사
책임 분리: UserService는 회원 관리, EmailService는 이메일만 담당!
2. 개방-폐쇄 원칙 (OCP: Open/Closed Principle)
확장에는 열려 있고, 수정에는 닫혀 있어야 한다.
위반한 코드
class PaymentService {
public void pay(String type) {
if (type.equals("kakao")) {
// 카카오 결제
} else if (type.equals("naver")) {
// 네이버 결제
}
}
}
Java
복사
새로운 결제 수단 추가 시 기존 코드를 수정해야 함.
올바른 코드 (다형성 활용)
interface PayStrategy {
void pay();
}
class KakaoPay implements PayStrategy {
public void pay() {
System.out.println("카카오 결제 완료");
}
}
class NaverPay implements PayStrategy {
public void pay() {
System.out.println("네이버 결제 완료");
}
}
class PaymentService {
public void processPayment(PayStrategy strategy) {
strategy.pay(); // 확장에는 열려있고, 기존 코드는 수정 필요 없음
}
}
Java
복사
새로운 결제 방식은 PayStrategy만 구현하면 끝! OCP 준수 
3. 리스코프 치환 원칙 (LSP: Liskov Substitution Principle)
자식 클래스는 부모 클래스를 대체할 수 있어야 한다.
위반한 코드
class Bird {
public void fly() {
System.out.println("날아갑니다");
}
}
class Ostrich extends Bird {
public void fly() {
throw new UnsupportedOperationException("타조는 날지 못해요");
}
}
Java
복사
Bird 타입으로 Ostrich를 사용하면 예외 발생 → LSP 위반
올바른 코드 (추상화 분리)
abstract class Bird { }
interface Flyable {
void fly();
}
class Sparrow extends Bird implements Flyable {
public void fly() {
System.out.println("참새가 날아갑니다");
}
}
class Ostrich extends Bird {
// 날지 않는 새
}
Java
복사
날 수 있는 새만 Flyable을 구현 → 부모-자식 대체 가능!
4. 인터페이스 분리 원칙 (ISP: Interface Segregation Principle)
큰 인터페이스를 여러 개의 작은 인터페이스로 나누어야 한다.
위반한 코드
interface Worker {
void work();
void eat();
}
class Robot implements Worker {
public void work() { /* 작업 */ }
public void eat() {
// 로봇은 밥을 먹지 않음! (불필요한 메소드)
}
}
Java
복사
Robot은 eat()이 필요 없음 → ISP 위반
올바른 코드
interface Workable {
void work();
}
interface Eatable {
void eat();
}
class Human implements Workable, Eatable {
public void work() { /* 일하기 */ }
public void eat() { /* 밥먹기 */ }
}
class Robot implements Workable {
public void work() { /* 일하기 */ }
}
Java
복사
필요한 인터페이스만 구현하게 분리!
5. 의존 역전 원칙 (DIP: Dependency Inversion Principle)
상위 모듈은 하위 모듈에 의존하지 말고, 둘 다 추상화에 의존해야 한다.
위반한 코드
class MySQLDatabase {
public void save() {
System.out.println("MySQL에 저장");
}
}
class OrderService {
private MySQLDatabase database = new MySQLDatabase(); // 구체 클래스에 의존
public void order() {
database.save();
}
}
Java
복사
OrderService가 구체 MySQLDatabase에 강하게 결합 → DIP 위반
올바른 코드 (인터페이스 도입)
interface Database {
void save();
}
class MySQLDatabase implements Database {
public void save() {
System.out.println("MySQL에 저장");
}
}
class OrderService {
private Database database; // 인터페이스에 의존
public OrderService(Database database) {
this.database = database;
}
public void order() {
database.save();
}
}
Java
복사
OrderService는 Database 인터페이스에만 의존 → 다른 DB로 교체도 유연!
정리 요약
원칙 | 핵심 한 줄 요약 |
SRP | 클래스는 하나의 책임만 가져야 함 |
OCP | 확장엔 열려있고, 수정엔 닫혀야 함 |
LSP | 자식 클래스는 부모를 대체 가능해야 함 |
ISP | 인터페이스는 작게 나누고 필요한 것만 구현 |
DIP | 구현체가 아닌 추상화에 의존해야 함 |



