자주 사용되는 디자인 패턴에 대해 알아보자 (springboot)
Spring Boot 개발에서 꼭 알아야 할 디자인 패턴
1. 싱글턴 패턴 (Singleton Pattern)
싱글턴 패턴은 객체를 하나만 생성하여 모든 클라이언트가 동일한 인스턴스를 공유하도록 하는 패턴입니다. Spring에서는 주로 @Service, @Component, @Repository 등의 어노테이션을 사용하여 빈을 생성할 때 싱글턴을 기본으로 사용합니다.
import org.springframework.stereotype.Service;
@Service
public class SingletonService {
private static SingletonService instance;
private SingletonService() {}
public static SingletonService getInstance() {
if (instance == null) {
instance = new SingletonService();
}
return instance;
}
public String getMessage() {
return "싱글턴 패턴 예제!";
}
}
설명: SingletonService 클래스는 getInstance() 메서드를 통해 객체를 한 번만 생성하고, 그 후에는 동일한 인스턴스를 반환합니다.
2. 전략 패턴 (Strategy Pattern)
전략 패턴은 알고리즘을 클래스화하여 각각의 전략을 교환 가능하게 만드는 패턴입니다. Spring에서는 비즈니스 로직을 다양한 전략 객체로 나누어 사용하는 경우가 많습니다.
// 전략 인터페이스
public interface PaymentStrategy {
void pay();
}
// 콘크리트 전략 1
public class CreditCardPayment implements PaymentStrategy {
@Override
public void pay() {
System.out.println("신용카드로 결제");
}
}
// 콘크리트 전략 2
public class PaypalPayment implements PaymentStrategy {
@Override
public void pay() {
System.out.println("PayPal로 결제");
}
}
// Context
public class PaymentService {
private PaymentStrategy paymentStrategy;
public PaymentService(PaymentStrategy paymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
public void executePayment() {
paymentStrategy.pay();
}
설명: PaymentService 클래스는 PaymentStrategy 인터페이스를 통해 결제 방법을 선택할 수 있게 하며, 필요에 따라 결제 전략을 변경할 수 있습니다.
3. 팩토리 패턴 (Factory Pattern)
팩토리 패턴은 객체를 생성하는 인터페이스를 제공하고, 구체적인 클래스의 인스턴스는 서브클래스에서 결정하도록 하는 패턴입니다. Spring에서는 빈을 자동으로 생성할 때 팩토리 메서드 방식이 많이 사용됩니다.
// 팩토리 인터페이스
public interface Vehicle {
void drive();
}
// 콘크리트 제품 1
public class Car implements Vehicle {
@Override
public void drive() {
System.out.println("자동차를 운전");
}
}
// 콘크리트 제품 2
public class Bike implements Vehicle {
@Override
public void drive() {
System.out.println("자전거를 타기");
}
}
// 팩토리 클래스
public class VehicleFactory {
public Vehicle createVehicle(String type) {
if ("car".equalsIgnoreCase(type)) {
return new Car();
} else if ("bike".equalsIgnoreCase(type)) {
return new Bike();
}
return null;
}
}
설명: VehicleFactory 클래스는 createVehicle() 메서드를 통해 조건에 맞는 객체를 생성하여 반환합니다.
4. 옵저버 패턴 (Observer Pattern)
옵저버 패턴은 한 객체의 상태 변화가 있을 때, 그것을 의존하고 있는 객체들에게 자동으로 알리는 패턴입니다. Spring에서는 ApplicationEventPublisher를 활용하여 이벤트 리스너 패턴을 구현할 때 사용됩니다.
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Component;
@Component
public class UserService implements ApplicationEventPublisherAware {
private ApplicationEventPublisher publisher;
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
this.publisher = publisher;
}
public void createUser(String username) {
System.out.println("사용자 생성: " + username);
publisher.publishEvent(new UserCreatedEvent(this, username));
}
}
public class UserCreatedEvent extends ApplicationEvent {
private String username;
public UserCreatedEvent(Object source, String username) {
super(source);
this.username = username;
}
public String getUsername() {
return username;
}
}
@Component
public class UserCreatedEventListener {
@EventListener
public void onUserCreated(UserCreatedEvent event) {
System.out.println("새로운 사용자 생성됨: " + event.getUsername());
}
}
설명: UserService는 새로운 사용자가 생성될 때 UserCreatedEvent 이벤트를 발행하고, UserCreatedEventListener는 이를 구독하여 알림을 받습니다.
5. 데코레이터 패턴 (Decorator Pattern)
데코레이터 패턴은 객체에 새로운 기능을 동적으로 추가할 수 있는 패턴입니다. Spring에서는 주로 AOP(Aspect-Oriented Programming)에서 사용되며, 메서드 실행 전후에 추가적인 작업을 할 때 사용됩니다.
public interface Coffee {
double cost();
}
public class SimpleCoffee implements Coffee {
@Override
public double cost() {
return 5.0;
}
}
public class MilkDecorator implements Coffee {
private Coffee decoratedCoffee;
public MilkDecorator(Coffee coffee) {
this.decoratedCoffee = coffee;
}
@Override
public double cost() {
return decoratedCoffee.cost() + 1.5;
}
}
public class SugarDecorator implements Coffee {
private Coffee decoratedCoffee;
public SugarDecorator(Coffee coffee) {
this.decoratedCoffee = coffee;
}
@Override
public double cost() {
return decoratedCoffee.cost() + 0.5;
}
}
설명: SimpleCoffee 객체에 MilkDecorator와 SugarDecorator를 추가하여 커피의 비용을 동적으로 변경할 수 있습니다.
결론
위에서 소개한 디자인 패턴들은 Spring Boot 애플리케이션에서 자주 사용되는 패턴들이며, 이를 통해 코드의 재사용성, 유지보수성 및 확장성을 높일 수 있습니다.