Server/Spring Boot

자주 사용되는 디자인 패턴에 대해 알아보자 (springboot)

hoonylab 2025. 4. 28. 17:44
728x90
반응형

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 애플리케이션에서 자주 사용되는 패턴들이며, 이를 통해 코드의 재사용성, 유지보수성 및 확장성을 높일 수 있습니다.

728x90
반응형