디자인 패턴은 단순히 "멋진 코드"를 만들기 위한 도구가 아닙니다. 실제 개발 현장에서 발생하는 고질적인 문제들을 해결하기 위해 검증된 재사용 가능한 솔루션이죠.
하지만 패턴에 집착하다 보면 오히려 코드가 비대해지는 '패턴 만능주의'에 빠지기 쉽습니다. 오늘은 실무 사례를 통해 패턴을 똑똑하게 활용하는 방법과 남용을 방지하는 원칙을 살펴보겠습니다.

1. 실무 프로젝트 속 디자인 패턴 사례
1.1 Singleton 패턴: 자원 관리의 효율화
[Problem] 데이터베이스 연결이나 로그 기록기 객체가 호출될 때마다 생성된다면? 메모리 낭비는 물론, 데이터 정합성이 깨질 위험이 있습니다.
[Solution] 객체 생성을 단 하나로 제한하여 시스템 전반에서 동일한 자원에 접근하도록 제어합니다.
// 실무 권장 방식: Bill Pugh Singleton (LazyHolder)
public class DatabaseConnection {
private DatabaseConnection() {}
private static class Holder {
private static final DatabaseConnection INSTANCE = new DatabaseConnection();
}
public static DatabaseConnection getInstance() {
return Holder.INSTANCE;
}
}
- 장점: 리소스 절약 및 데이터 접근 일관성 유지.
- 주의: 싱글톤은 전역 상태를 만들기 때문에 테스트가 어려워질 수 있습니다.
1.2 Factory 패턴: 객체 생성의 유연성 확보
[Problem] 클라이언트 코드에서 new Circle(), new Rectangle()을 직접 호출하면, 새로운 도형이 추가될 때마다 클라이언트 코드를 수정해야 합니다.
[Solution] 객체 생성 로직을 팩토리 클래스에 위임하여 결합도를 낮춥니다.
public class ShapeFactory {
public static Shape getShape(String type) {
return switch (type.toUpperCase()) {
case "CIRCLE" -> new Circle();
case "RECTANGLE" -> new Rectangle();
default -> throw new IllegalArgumentException("Unknown shape type");
};
}
}
- 장점: 구체적인 클래스 타입을 몰라도 객체를 생성할 수 있어 확장에 유리합니다. (OCP 준수)
2. 패턴의 결합: Observer + Singleton
실제 프로젝트에서는 하나의 패턴만 쓰기보다 여러 패턴을 조합할 때 시너지가 납니다. 가장 대표적인 사례가 채팅 알림 시스템입니다.
- Singleton: 메시지를 수신하고 관리하는 MessageCenter를 단 하나만 유지합니다.
- Observer: 새로운 메시지가 올 때마다 구독 중인 여러 UI 컴포넌트에 동시에 알림을 보냅니다.
이 조합을 통해 중앙 집중식 데이터 관리와 실시간 상태 업데이트를 동시에 달성할 수 있습니다.
3. 디자인 패턴 남용 방지: "Simple is Best"
디자인 패턴이 강력하다고 해서 모든 곳에 적용해서는 안 됩니다. 패턴 남용은 오버 엔지니어링(Over-engineering)을 초래합니다.
💡 반드시 기억해야 할 3대 원칙
| 원칙 | 설명 | 적용 방법 |
| KISS | Keep It Simple, Stupid | 가장 단순한 방법으로 해결할 수 있다면 패턴을 쓰지 마세요. |
| YAGNI | You Aren't Gonna Need It | "나중에 필요할 것 같아서" 미리 패턴을 적용하지 마세요. |
| DRY | Don't Repeat Yourself | 중복 코드가 발생할 때 비로소 패턴 도입을 검토하세요. |
⚠️ 이런 징후가 보이면 남용입니다!
- 클래스 파일이 너무 많아져서 로직을 따라가기 힘들다.
- 간단한 기능을 수정하는데 5개 이상의 클래스를 건드려야 한다.
- 동료 개발자가 코드를 이해하는 데 한 시간 넘게 설명이 필요하다.
4. 마무리하며: 리팩토링으로 도입하라
디자인 패턴을 적용하기 가장 좋은 타이밍은 설계 단계가 아니라 리팩토링 단계입니다. 처음에는 가장 단순하게 코드를 짜고, 중복이 발생하거나 확장이 어려워지는 시점에 해당 문제를 해결할 수 있는 패턴을 도입하세요.
패턴은 목적이 아니라 수단이어야 합니다. 프로젝트의 규모와 팀원들의 숙련도에 맞춰 적절한 균형을 찾는 것이 진정한 시니어 개발자의 역량입니다.
글이 도움이 되셨다면 공감과 구독 부탁드립니다! 여러분의 프로젝트에서는 어떤 패턴이 가장 유용했나요? 댓글로 경험을 공유해주세요!
'Mobile & App Stack > Java Software Architecture & Patterns' 카테고리의 다른 글
| 고전 GoF를 넘어선 최신 디자인 패턴 트렌드: MSA부터 리액티브까지 (0) | 2025.01.08 |
|---|---|
| 이터레이터 패턴: 데이터 구조와 상관없이 일관되게 순회하는 법 (0) | 2025.01.06 |
| 비지터 패턴(Visitor): 기존 코드 수정 없이 기능을 무한 확장하는 법 (0) | 2025.01.05 |
| 상태 패턴(State Pattern): if-else 조건문 지옥에서 탈출하는 법 (0) | 2025.01.04 |
| 템플릿 메서드 패턴: 중복 코드를 줄이는 상속의 기술 (Java 예제) (0) | 2025.01.03 |