1. 디자인 패턴이란?
디자인 패턴은 소프트웨어 설계 시 반복적으로 등장하는 문제를 해결하기 위한 일종의 '템플릿'이다. Java Spring에서는 프레임워크 특성상 구조적인 패턴(예: MVC)이나 생성/행위 패턴을 많이 활용한다.
실제로 Spring 기반 프로젝트를 개발하다 보면, 작은 규모의 서비스라도 다양한 디자인 패턴이 유기적으로 사용되는 것을 볼 수 있습니다. 각 컴포넌트가 자신의 책임에 집중하고, 변화에 유연하게 대응할 수 있도록 설계하는 과정에서 자연스럽게 전략(Strategy), 프록시(Proxy), 빌더(Builder) 등 다수의 패턴이 녹아들게 됩니다.
2. 시기별 디자인 패턴 사용 경향
시기 | 특징 | 주로 사용된 패턴 |
Spring Framework 2.x | XML 기반 설정, DI/IoC 초창기 | Singleton, Factory, Proxy, Template Method |
Spring 3.x ~ 4.x | Java Config 전환, AOP 정착 | Strategy, Decorator, Observer, Command |
Spring Boot | Auto-configuration, Starter 기반 설정 최소화 | Builder, Adapter, Chain of Responsibility, Specification |
3. 주요 디자인 패턴 정리 및 실무 예제
Singleton 패턴
- 정의: 인스턴스를 하나만 생성해 공유
- Spring 적용: 기본 Bean scope가 Singleton
- 대표 클래스: Spring의 모든 @Component, @Service, @Repository
- UML (Text 기반):
+----------------+
| Singleton |
+----------------+
| - instance |
+----------------+
| + getInstance()|
+----------------+
- 실무 예제:
@Service
public class NotificationService {
public void send(String message) {
System.out.println("Sending message: " + message);
}
}
Factory 패턴
- 정의: 객체 생성 로직을 캡슐화
- Spring 적용: BeanFactory, FactoryBean
- 대표 클래스: LocalSessionFactoryBean, SqlSessionFactoryBean
- UML (Text 기반):
+-------------+
| Product |
+-------------+
^ ^
| |
+---------------------+
|ConcreteProductA/B |
+---------------------+
^
|
+---------------------+
| ProductFactory |
| +createProduct() |
+---------------------+
- 실무 예제:
public class AnimalFactory {
public static Animal createAnimal(String type) {
return switch (type) {
case "dog" -> new Dog();
case "cat" -> new Cat();
default -> throw new IllegalArgumentException("Unknown type");
};
}
}
Proxy 패턴
- 정의: 대리 객체를 통해 원래 객체 제어
- Spring 적용: AOP (Aspect Oriented Programming)
- 대표 클래스: ProxyFactoryBean, @Transactional
- UML (Text 기반):
+---------+
| Subject |
+---------+
^ ^
| |
+--------------+ +--------+
| RealSubject | | Proxy |
+--------------+ +--------+
|
v
+-------------+
| RealSubject |
+-------------+
- 실무 예제:
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.example.service.*.*(..))")
public void logBefore() {
System.out.println("메서드 실행 전 로그 출력");
}
}
Template Method 패턴
- 정의: 알고리즘 골격을 정의하고, 일부 단계는 서브클래스에서 구현
- Spring 적용: JdbcTemplate, RestTemplate
- 대표 클래스: JdbcTemplate, AbstractController
- UML (Text 기반):
+------------------+
| AbstractClass |
+------------------+
| +templateMethod()|
| +primitiveOp1() |
| +primitiveOp2() |
+------------------+
^
|
+------------------+
| ConcreteClass |
+------------------+
| +primitiveOp1() |
| +primitiveOp2() |
+------------------+
- 실무 예제:
public abstract class AbstractTask {
public void execute() {
start();
process();
end();
}
protected abstract void process();
private void start() { System.out.println("Start"); }
private void end() { System.out.println("End"); }
}
Strategy 패턴
- 정의: 알고리즘을 클래스로 분리해 캡슐화
- Spring 적용: AuthenticationProvider, ViewResolver
- 대표 클래스: HandlerMethodArgumentResolver
- UML (Text 기반):
+------------+
| Strategy |
+------------+
^ ^
| |
+-------------------+
|ConcreteStrategies |
+-------------------+
^
|
+-----------+
| Context |
+-----------+
| -strategy |
| +execute()|
+-----------+
- 실무 예제:
public interface PaymentStrategy {
void pay(int amount);
}
public class CreditCardPayment implements PaymentStrategy {
public void pay(int amount) {
System.out.println("Paid " + amount + " using credit card.");
}
}
Builder 패턴
- 정의: 복잡한 객체 생성을 단계별로 처리
- Spring 적용: ResponseEntity.builder(), Lombok @Builder
- 대표 클래스: ResponseEntity, User.builder()
- UML (Text 기반):
+-----------+ +-----------+
| Director | ----> | Builder |
+-----------+ +-----------+
^
|
+------------------+
| ConcreteBuilder |
+------------------+
|
v
+---------+
| Product |
+---------+
- 실무 예제:
@Builder
public class User {
private String name;
private int age;
}
Adapter 패턴
- 정의: 인터페이스 호환을 위한 중간 계층
- Spring 적용: HandlerAdapter, MessageConverter
- 대표 클래스: HttpMessageConverter, HandlerAdapter
- UML (Text 기반):
+--------+
| Target |
+--------+
^
|
+--------+
| Adapter|
+--------+
|
v
+--------+
| Adaptee|
+--------+
- 실무 예제:
public interface MediaPlayer {
void play(String fileName);
}
public class AudioPlayer implements MediaPlayer {
public void play(String fileName) {
System.out.println("Playing " + fileName);
}
}
Specification 패턴
- 정의: 조건을 조합해 쿼리 작성
- Spring 적용: JpaSpecificationExecutor
- 대표 클래스: Specification<T>
- UML (Text 기반):
+------------------+
| Specification |
+------------------+
| +isSatisfiedBy() |
| +and(), or(), not()|
+------------------+
^
|
+----------------------------+
| ConcreteSpecification |
+----------------------------+
- 실무 예제:
Specification<User> hasName(String name) = (root, query, cb) -> cb.equal(root.get("name"), name);
4. 목적별 디자인 패턴 추천 가이드
Spring 프로젝트에서 상황에 따라 어떤 디자인 패턴을 적용하면 좋을지 정리하면 다음과 같습니다:
목적/상황 | 추천 패턴 | 설명 |
JPA 동적 쿼리 처리 | Specification | 조건 조합 및 유연한 쿼리 생성을 위해 적합 |
다양한 외부 시스템 연계 | Adapter, Template Method | 연계 대상별로 추상화하여 유연하게 연동 가능 |
복잡한 객체 생성 | Builder | DTO나 Response 객체를 생성할 때 단계적 설정이 가능 |
비즈니스 로직 알고리즘 분리 | Strategy | 정책, 계산 방식, 인증처리 등 알고리즘 선택에 유리 |
횡단 관심사 처리 | Proxy | 트랜잭션, 로깅, 인증/인가 등 AOP 기반 처리 |
템플릿 제공 후 확장 유도 | Template Method | API 호출, DB 연동 등 공통 로직 제공 후 커스터마이징 허용 |
서로 다른 구현 통합 필요 | Adapter | 외부 API, 레거시 시스템 등을 일관된 인터페이스로 변환 |
이 표를 바탕으로 실무 상황에 맞는 패턴을 선택하면 아키텍처의 유연성과 유지보수성이 크게 향상됩니다
'Back-End > Java & Spring' 카테고리의 다른 글
Factory 패턴 개념 (0) | 2025.05.11 |
---|---|
싱글톤 패턴 개념& Spring Bean Scope (0) | 2025.05.11 |
Java GC 로그 해석과 튜닝 전략 정리 (0) | 2025.05.10 |
Java GC 알고리즘 정리 (0) | 2025.05.10 |
CORS 오류 해결하기(Spring) (0) | 2025.03.02 |