본문 바로가기
반응형
Design Pattern

[디자인 패턴] 전략(Strategy) 패턴

by brightGarden02 2024. 2. 8.

전략패턴은 (기능을 가지고 있는)컨텍스트에서 알고리즘(전략)을 별도로 분리하는 설계 방법이다.

 

 

@Service
public class TicketSeller {
    
    @Transactional
    public CreateReservationResponse createReservation(CreateReservationRequest dto) {
		
        //예약 가능한 좌석인지 확인
        performanceSeatInfo.isReserve(ReserveStatus.ENABLE);
     	
     }
 }

전략패턴에 집중하기 위해 어노테이션, 기타 코드는 생략하였다.

TicketSeller는 공연에 대한 비즈니스 로직을 처리하는 서비스이다.

 

 

 

@Entity
public class PerformanceSeatInfo extends BaseEntity {

	public void isReserve(ReserveStatus status) {
        if(!this.isReserve.equalsIgnoreCase(status.getValue())) {
            throw new ServiceException(StatusCode.RESERVE_NOT_VALID_PERFORMANCE_SEAT);
        }
    }
}

PerformanceSeatInfo는 공연에 대한 정보를 가지고 있는 엔터티이다.

 

TicketSeller에서 엔터티인 PerformanceSeatInfo에 있는 isReserve() 메서드를 이용하여 예약 가능한 좌석인지 확인한다.

엔터티에 isReserve() 메서드를 구현함으로 캡슐화를 했었다.

그러나 예약 관련 비즈니스 로직이 추가될 경우 엔터티에 비즈니스 로직이 강하게 결합되는 문제가 생긴다. 따라서 전략패턴을 이용하여 엔터티에 결합된 비즈니스 로직을 분리해보겠다.

 

 

 

public interface ReserveStrategyInterface {
    void isReserveEnable(String isReserve);
}


@Service
public class ConcreteEnableReserveStrategy implements ReserveStrategyInterface {

    @Override
    public void isReserveEnable(String isReserve) {
        if(!ReserveStatus.ENABLE.getValue().equalsIgnoreCase(isReserve)) {
            throw new ServiceException(StatusCode.RESERVE_NOT_VALID_PERFORMANCE_SEAT);
        }
    }
}


@Service
public class ReserveStrategy {
    public void isReserveEnable(ReserveStrategyInterface reserveStrategy, String isReserve) {
        reserveStrategy.isReserveEnable(isReserve);
    }
}

 

ReserveStrategyInterface 인터페이스와 이를 구현하는 ConcreteEnableReserveStrategy를 구현하였다.

그리고 변경 가능한 코드를 위해 ReserveStretegy에 있는 isReserveEnable()메서드 첫번째 파라미터를 인터페이스로구현하였다.

 

 

 

@Service
@RequiredArgsConstructor
public class TicketSeller {
    private final ReserveStrategy reserveStrategy;

    @Transactional
    public CreateReservationResponse createReservation(CreateReservationRequest dto) {

        // 예약 가능한 좌석인지 확인
        // 첫번째 파라미터에 추가되는 예약 상태 관련 클래스로 변경하여 주입 가능
        reserveStrategy.isReserveEnable(new ConcreteEnableReserveStrategy(), performanceSeatInfo.getIsReserve());
    }
}

TicketSeller 서비스에서 ReserveStrategy 클래스를 @RequiredArgsConstructor로 생성자 DI를 하고

reserveStrategy.isReserveEnable() 메서드를 통해 변경 가능한 ConcreteEnableReserveStrategy를 넣도록 구현했다.

전략 패턴 덕분에 ConcreteEnableReserveStrategy 대신 새로운 ConcreteDisableReserveStrategy 등등으로 변경하여 주입이 가능하다.

 

 

 

이로써 전략패턴을 통해 엔터티에 결합된 비즈니스 로직을 제거하고 예약 확인 관련 비즈니스 로직이 확장될 경우 변경에 유연한 코드 작성이 가능한 코드가 되었다.

 

 

 

코드는 현재 진행중인 원티드 "프리온보딩 2월 백엔드 챌린지 사전과제"에서 작성한 코드이다.

https://github.com/brightGarden02/wanted-preonboarding-challenge-backend-16

 

GitHub - brightGarden02/wanted-preonboarding-challenge-backend-16: 원티드 프리온보딩 백엔드 챌린지 사전과제

원티드 프리온보딩 백엔드 챌린지 사전과제. Contribute to brightGarden02/wanted-preonboarding-challenge-backend-16 development by creating an account on GitHub.

github.com

 

 

참고 책:

댓글


반응형
반응형