ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Facade 패턴을 통해 코드의 복잡함을 숨겨서 간단해 보이도록 해보자
    Design Patterns 2023. 11. 8. 17:02

    들어가기 전

    이전 글

    이전 과정은 뇌를 빼고 작성했던 코드를 리팩토링 하는 과정을 거쳐봤다.
    해당 글에서는 3가지 일을 맡고 계신 비즈니스 로직의 한 메소드를 디자인 패턴을 통해 간단하게 보이도록 해줄 예정이다.

    Facade 디자인 패턴

    복잡한 로직을 하나로 합쳐서 외부에서는 간단하게 사용할 수 있도록 만드는 것이다.
    즉 복잡한 로직을 하나의 인터페이스로 정리해 주는 것이다.

    장점은?

    1. 복잡한 시스템을 단순화하여 클라이언트가 쉽게 이해하고 사용할 수 있다.

    2. 각 도메인 로직에 대한 독립성을 높여 유지보수와 확장성을 향상시킬 수 있다.

    3. 도메인 서비스 간의 느슨한 결합을 통해 시스템 변경에 대한 클라이언트의 영향을 최소화한다.

    단점은?

    Facade 패턴을 구현한 클래스가 너무 많은 책임을 가지게 되면 복잡성이 증가할 수 있다.

    정리해보면

    여러 도메인의 서비스 계층의 독립성을 유지하여 단위 테스트를 쉽게 할 수 있도록 해준다.
    그러면서 수행 해야할 동작은 하나로 합쳐서 관리를 할 수 있으니 코드의 응집도는 높아진다.

    도메인 자체의 코드는 간단해지고 여러 도메인이 필요해서 복잡해질 코드는 따로 빼서 관리할 수 있다는 것이다.

    그럼 적용해보자

    @Service  
    public class AnswerService {  
      
    	private final AnswerRepository answerRepository;  
    	private final MemberService memberService;  
    	private final QuestionService questionService;  
    	private final AnswerMapper answerMapper;  
    	  
    	public AnswerService(AnswerRepository answerRepository, MemberService memberService,  
    	QuestionService questionService, AnswerMapper answerMapper) {  
    		this.answerRepository = answerRepository;  
    		this.memberService = memberService;  
    		this.questionService = questionService;  
    		this.answerMapper = answerMapper;  
    	}  
    	  
    	@Transactional  
    	public void create(AnswerRequest request, Long memberId) {  
    		Member findedMember = memberService.findById(memberId);  
    		Question findedQuestion = questionService.findById(request.questionId());  
    		answerRepository.save(answerMapper.answerRequestToEntity(request, findedQuestion, findedMember));  
    	}  
    }
    

    지금 create 메소드 하나 때문에 외부 도메인 서비스 로직이 2개에 의존성을 가지고 있다.

    이 부분을 따로 Facade 패턴으로 정리해볼 것이다.

    적용 후

    @Service  
    public class AnswerService {  
      
    private final AnswerRepository answerRepository;  
    private final AnswerFacade answerFacade;  
      
    public AnswerService(AnswerRepository answerRepository, AnswerFacade answerFacade) {  
    	this.answerRepository = answerRepository;  
    	this.answerFacade = answerFacade;  
    }  
      
    	@Transactional  
    	public void create(AnswerRequest request, Long memberId) {  
    		Answer answer = answerFacade.create(request, memberId);  
    		answerRepository.save(answer);  
    	}  
    }
    
    public interface AnswerFacade {  
      
    	Answer create(AnswerRequest request, Long memberId);  
    }
    
    @Component  
    public class AnswerFacadeImpl implements AnswerFacade {  
      
    	private final MemberService memberService;  
    	private final QuestionService questionService;  
    	private final AnswerMapper answerMapper;  
    	  
    	public AnswerFacadeImpl(MemberService memberService, QuestionService questionService,  
    	AnswerMapper answerMapper) {  
    		this.memberService = memberService;  
    		this.questionService = questionService;  
    		this.answerMapper = answerMapper;  
    	}  
    	  
    	@Override
    	@Transactional
    	public Answer create(AnswerRequest request, Long memberId) {  
    		Member findedMember = memberService.findById(memberId);  
    		Question findedQuestion = questionService.findById(request.questionId());  
    		return answerMapper.answerRequestToEntity(request, findedQuestion, findedMember);  
    	}  
    }
    

    answerService는 answerRepository와 answerFacade에만 의존성을 가지고 있고, 외부 도메인 서비스들과 의존성은 Facade쪽에서 담당하게 되었다.
    여기서 @Transactional 어노테이션을 새로 달아준다.
    Transactional은 propagation의 기본값은 REQUIRED 설정으로 부모 메소드가 Transactional이 설정되어있다면 새로운 트랙잭션을 만들지 않는다.
    하지만 Facade 내의 메소드가 다른 곳에서 쓰일 수 있는점을 고려해서 새로 설정해준다.

    고민점

    일단 Facade 패턴을 통해 외부 도메인과 분리할 곳은 분리하고 합칠 곳은 합치는 방법을 통해 정리를 해봤는데, AnswerMapper의 위치가 고민이 된다.
    둘 다 위치해도 괜찮을지 좀 더 고민해보고 다시 정리해봐야겠다.

    댓글

Designed by black7375.