Decorator(데코레이터) 패턴이란?

  • 기능을 동적으로 유연하게 확장하는 디자인 패턴으로, 객체의 결합을 통해 이루어진다.
  • GoF 패턴 중 구조(Structural) 패턴으로 분류된다.
    • 구조 패턴: 클래스나 객체를 조합해 더 큰 구조를 만드는 패턴

추상적으로만 알고 있었는데, 이번에 적용해볼 기회가 생겼다.

적용하게 된 동기

AccountService 예시

@Service
@RequiredArgsConstructor
public class AccountService {

    private final AccountRepository accountRepository;

    /**
     * Sign-In
     */
    @Transactional
    public void signIn(final SignInRequestVo requestVo) {

        final Optional<Account> accountOptional = accountRepository.findById(requestVo.getId());

        final Account account =
                accountOptional.orElseThrow(() -> new CommonException(ResponseCode.USER_NOT_EXISTED));

        ...
    }
}

위는 Sign-In(로그인)을 수행하는 AccountService의 일부 로직을 발췌한 코드이다.


AccountRepository라는 JPA Repository Interface를 이용하여 Account를 Optional 객체로 감싸서 가져오고, Account가 존재하지 않을 경우 예외 처리를 한다.


기능상으로는 멀쩡한 코드이지만, 문제는 이러한 코드들(JPA Repository에서 Optional로 받아와서 예외처리)이 서비스 단에서 무수히 많이 반복된다는 것이다.


이는 구조적으로 정갈하지 못하다.

Service Layer는 핵심 비즈니스 로직을 수행하는 것에 집중해야 한다. 핵심 로직이 아닌 나머지 코드들은 서비스 단에서 걷어내는 것이 코드 가독성 측면에서 이롭다.

따라서 이처럼 반복되는 코드는 구조적으로 개선할 필요가 있다고 판단했다.

 

데코레이터 패턴 적용 후

AccountRepositoryDecorator 예시

@RequiredArgsConstructor
@Component
public class AccountRepositoryDecorator {

    private final AccountRepository accountRepository;

    public Account findById(Long id) {
        final Optional<Account> accountOptional = accountRepository.findById(id);

        final Account account =
                accountOptional.orElseThrow(() -> new CommonException(ResponseCode.USER_NOT_EXISTED));

        return account;
    }

    ...

AccountService 예시

@Service
@RequiredArgsConstructor
public class AccountService {

    private final AccountRepositoryDecorator accountRepository;

    /**
     * Sign-In
     */
    @Transactional
    public void signIn(final SignInRequestVo requestVo) {

        final Account account = accountRepository.findById(requestVo.getId());

        ...
    }
}

 

  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기