1. SRP (단일 책임 원칙, Single Responsibility Principle)
한 클래스는 하나의 책임만 가져야 한다. 한 클래스가 너무 많은 일을 하게 되면 유지보수가 어려워진다.
예시
- 잘못된 예 : 하나의 클래스가 '보고서 생성' , '출력' , '이메일 발송' 책임까지 모두 담당한다.
class ReportService {
void generateReport() { /* 보고서 데이터 생성 */ }
void printReport() { /* 보고서 출력 */ }
void sendReportByEmail() { /* 보고서 이메일 발송 */ }
}
- 개선 : 각 클래스가 한 가지 책임만 맡는다.
class ReportGenerator { void generate() { /* 보고서 생성 */ } }
class ReportPrinter { void print() { /* 보고서 출력 */ } }
class EmailSender { void send() { /* 이메일 발송 */ } }
2. OCP (개방-폐쇄 원칙, Open/Closed Principle)
확장에는 열려 있고, 변경에는 닫혀 있어야 한다. 기능을 추가할 때 기존 코드를 수정하지 않고, 새로운 코드를 추가하도록 설계한다.
예시
- 잘못된 예 : 새로운 결제 방식 추가 시 `if 문` 을 계속 수정해야한다.
class PaymentService {
void pay(String type) {
if ("CARD".equals(type)) { /* 카드 결제 */ }
else if ("KAKAO".equals(type)) { /* 카카오페이 */ }
}
}
- 개선 : 새로운 결제 수단 추가 시 기존 코드 변경 없이 클래스만 추가한다.
interface Payment {
void pay();
}
class CardPayment implements Payment {
public void pay() { /* 카드 결제 */ }
}
class KakaoPayment implements Payment {
public void pay() { /* 카카오페이 */ }
}
class PaymentService {
void pay(Payment payment) {
payment.pay(); // 새로운 결제방식 추가해도 PaymentService 수정 없음
}
}
3. LSP (리스코프 치환 원칙, Liskov Substitution Principle)
부모 타입의 객체를 자식 타입으로 바꿔도 프로그램이 정상 동작해야 한다. 자식 클래스는 부모 클래스의 기능을 완전히 대체 가능해야 한다.
예시
- 잘못된 예 : 타조는 날지 못하는데, 부모 (Bird)는 날 수 있다고 가정
class Bird { void fly() {} }
class Ostrich extends Bird {
void fly() { throw new UnsupportedOperationException(); }
}
- 개선 : 날 수 있는 새와 없는 새를 분리하여 자식 클래스가 부모의 계약을 어기지 않도록 함
interface Bird {}
interface FlyableBird extends Bird { void fly(); }
class Sparrow implements FlyableBird { public void fly() {} }
class Ostrich implements Bird { /* 날 수 없는 새 */ }
4. ISP (인터페이스 분리 원칙, Interface Segregation Principle)
하나의 큰 인터페이스보다, 여러 개의 구체적이고 작은 인터페이스가 낫다. 사용하지 않는 메서드까지 구현하게끔 하면 안된다.
예시
- 잘못된 예 : 프린터인데 스캔/팩스 메서드까지 구현 강제
interface Machine {
void print();
void scan();
void fax();
}
class SimplePrinter implements Machine {
public void print() {}
public void scan() { /* 필요 없음 */ }
public void fax() { /* 필요 없음 */ }
}
- 개선 : 필요한 기능만 구현하도록 인터페이스 분리
interface Printer { void print(); }
interface Scanner { void scan(); }
class SimplePrinter implements Printer {
public void print() {}
}
5. DIP (의존관계 역전 원칙, Dependency Inversion Principle)
구현 클래스가 아니라, 추상화에 의존해야한다. 상위 모듈이 하위 모듈에 의존하면 결합도가 높아지고 변경에 취약하다.
예시
- 잘못된 예 : Computer 클래스가 특정 Keyboard, Monitor 클래스에 강하게 의존한다.
class Keyboard {}
class Monitor {}
class Computer {
private Keyboard keyboard = new Keyboard();
private Monitor monitor = new Monitor();
}
- 개선 : 인터페이스에 의존하므로 구현체 변경 시 코드 수정 필요 없음
interface Keyboard {}
interface Monitor {}
class LogitechKeyboard implements Keyboard {}
class SamsungMonitor implements Monitor {}
class Computer {
private Keyboard keyboard;
private Monitor monitor;
public Computer(Keyboard keyboard, Monitor monitor) {
this.keyboard = keyboard;
this.monitor = monitor;
}
}'Java' 카테고리의 다른 글
| [Java] 자바 변수 4가지 정리 (전역, 지역, 정적, 멤버 변수) (0) | 2025.11.10 |
|---|---|
| [Java] 원시타입(Primitive Type)과 참조타입(Reference Type) (0) | 2025.10.14 |
| [Java] 스트림(Stream)에 대하여 (0) | 2025.10.14 |
| [Java] 실수를 나타내는 Double, double, float, decimal 의 차이 (0) | 2025.10.13 |
| [Java] POJO(Plain Old Java Object) (0) | 2025.09.16 |
