728x90

들어가며


4편에서 외부에서 내부로 데이터를 보낼 것이라고 예고했다.

//        request -> UseCase(inbounded port) -> Service (biz logic)

 

 

 

Hexagonal 아키텍처로 회원정보 인바운드 어댑터 개발 MSA프로젝트[4]

들어가며 개발의 흐름과 Hexagonal 아키텍처 구조에서 각 클래스와 인터페이스가 어떻게 상호작용하는지를 확실하게 이해하기 위해 기록하려고 한다. 어댑터 개발 앞선 3편에서는 Membership 도메인

wooltech.tistory.com

UseCase 인터페이스는 뭐하는 곳인가?


우선 인바운드 포트는 UseCase와 Command로 구성된다.

 

Controller에서 Request를 Port로 전달하는데, Port에서 이를 전달 받는 곳이 UseCase다.

그리고 UseCase는 Service가 비즈니스 로직을 수행할 수 있게 도움을 주는 역할을 한다.

public interface RegisterMembershipUseCase {
    Membership registerMembership(RegisterMembershipCommand command);

}

 

registerMembership메서드는 Command 명령객체를 받아 Membership객체를 만든다고 정의되어 있다.

갑자기 Command라는 객체가 등장했다!

 

좋은 객체지향 프로그래밍 DIP 준수


Controller에서는 Request를 바로 UseCase로 전달하지 않고 Command 패턴을 사용한다.

이유는 의존성 역전 원칙을 준수하기 위해서다.

 

좋은 객체 지향 SOLID를 위한 config 구성창 Jav Spring 프레임워크의 기본 (4)

좋은 객체 지향 프로그래밍 SOLID 용어 개념 SRP 단일 책임 원칙 = 하나의 클래스는 하나의 책임을 가짐 OCP 개방 및 폐쇄 원칙 = 확장에는 열려 있으나, 변경에는 닫힘 LSP 리스코프 치환 원칙 = 객체

wooltech.tistory.com

 

좋은 객체 프로그래밍은 서로간의 구체적인 의존을 피하고, 추상화에 의존해야 한다.

즉, Controller의 request가 변경되더라도 UseCase에는 영향을 주지 않아야 한다.

 

회원 등록을 위해 정보 캡슐화하기


@Builder
@Data
@EqualsAndHashCode(callSuper = false)
public class RegisterMembershipCommand extends SelfValidating<RegisterMembershipCommand> {
    // except membershipId, isValid

    @NotNull
    private String name;
    @NotNull
    private String address;
    @NotNull
    private String email;
    @AssertTrue
    private boolean isValid;
    private boolean isCorp;


    public RegisterMembershipCommand(String name, String address, String email, boolean isValid, boolean isCorp) {
        this.name = name;
        this.address = address;
        this.email = email;
        this.isValid = isValid;
        this.isCorp = isCorp;

        this.validateSelf();
    }
}

 

명령 객체를 사용하기 위해 RegisterMembershipCommand의 생성자를 초기화한다.

이제 RegisterMembershipCommand는 값을 받을 수 있다.

값으로 받을 name, address, email은 @NotNull로 빈값을 가지지 않음을 SelfValidating하고 있다.

 

빌더 패턴을 사용해 Command 객체 구현


RegisterMembershipCommand command = RegisterMembershipCommand.builder()
        .name(request.getName())
        .address(request.getAddress())
        .email(request.getEmail())
        .isValid(true)
        .isCorp(request.isCorp())
        .build();

 

다시 Controller로 돌아와서 request객체의 값을 get해서 빌더패턴을 통해 Command객체를 생성한다.

빌더 패턴은 선택적으로 필드값을 사용할 수 있고 순서에 영향을 받지 않는 등 유연한 장점을 갖는다.

 

생성자 주입을 통해 관계 설정


UseCase를 생성자 주입하여 만들어 둔 command객체를 통해 registerMembership메서드를 전달한다.

의존성 주입 방식으로 @RequiedArgsConsrtructor를 통해 생성자 주입을 사용하고 있다.

즉, Controller 클래스에서 UseCase 객체를 만들 수 있도록 한다.

@RequiredArgsConstructor
public class RegisterMembershipController {
    
    private final RegisterMembershipUseCase registerMembershipUseCase;
    
   	registerMembershipUseCase.registerMembership(command);

 

+ Recent posts