꾸준한 스터디
article thumbnail

필수가 아닌 선택적인 매개변수가 많을때 정적 팩터리와 생성자로 대응하기 쉽지 않다는 점이다.

 

점층적 생성자 패턴

- 선택 값을 하나씩 추가하여 생성자를 점층적으로 만드는 패턴이다.

 

매개변수의 개수나 타입이 일치하지 않을 경우 컴파일 오류를 통해 누락된 값을 확인할 수 있는 안전성을 가지고 있다.

 

그러나, 적당한 개수의 매개변수에 대한 점층적 생성자 패턴은 괜찮아 보일지 몰라도 점점 많아지는 생성자로 클래스 코드의 추가 수정 삭제등 유지보수에 대한 불편함이 있다.  또한 각 생성자의 의미, 어떠한 매개변수가 들어가야 하는지에 대한 가독성이 떨어진다.

public class Jwt {

    private static final String SECRET_KEY = "1234"; // JWT Secret Key

    private final String userIdx;
    private final String frIdx;
    private final String userId;
    private final String parId;
    private final String userNm;
    private final String parHp;
    private final String status;
    private final String userType;
    private final String loginUiType;
    private final Boolean checkPwd;

    //필수 값 생성자
    public Jwt(String userIdx, String userId, String userNm) {
        this(userIdx, userId, userNm, null);
    }

    public Jwt(String userIdx, String userId, String userNm, String userType) {
        this(userIdx, userId, userNm, userType, null);
    }

    public Jwt(String userIdx, String userId, String userNm, String userType, String frIdx) {
        this(userIdx, userId, userNm, userType, frIdx, null);
    }

    public Jwt(String userIdx, String userId, String userNm, String userType, String frIdx, String parId) {
        this(userIdx, userId, userNm, userType, frIdx, parId,null);
    }

    public Jwt(String userIdx, String userId, String userNm, String userType, String frIdx, String parId,
               String parHp) {
        this(userIdx, userId, userNm, userType, frIdx, parId, parHp, null);
    }

    public Jwt(String userIdx, String userId, String userNm, String userType, String frIdx, String parId,
               String parHp, String status) {
        this(userIdx, userId, userNm, userType, frIdx, parId, parHp, status, null);
    }

    public Jwt(String userIdx, String userId, String userNm, String userType, String frIdx, String parId,
               String parHp, String status, String loginUiType) {
        this(userIdx, userId, userNm, userType, frIdx, parId, parHp, status, loginUiType, true);
    }

    public Jwt(String userIdx, String userId,  String userNm, String userType, String frIdx, String parId,
               String parHp, String status,  String loginUiType, Boolean checkPwd) {
        this.userIdx = userIdx;
        this.frIdx = frIdx;
        this.userId = userId;
        this.parId = parId;
        this.userNm = userNm;
        this.parHp = parHp;
        this.status = status;
        this.userType = userType;
        this.loginUiType = loginUiType;
        this.checkPwd = checkPwd;
    }

 

자바 빈즈 패턴

- 매개 변수가 없는 기본 생성자로 객체를 생성 후 setter 메서드를 통하여 원하는 값을 설정하는 패턴이다.

 

일반적으로 사용되는 네이밍 컨벤션을 통해 값을 설정하고 가져 오는지에 대한 가독성 측면의 장점이 있다.

 

그러나, setter를 통한 값의 설정으로 여러번 호출하고 더 이상 변경이 없기 전까지 객체의 일관성이 없어진다.

위의 단점을 보완하고자 freeze라는 개념이 등장하는데, JavaScript에서 불변성을 보장하기 위해 사용된다고 한다.

public class Jwt {

    private static final String SECRET_KEY = "1234"; // JWT Secret Key

    private String userIdx;
    private String frIdx;
    private String userId;
    private String parId;
    private String userNm;
    private String parHp;
    private String status;
    private String userType;
    private String loginUiType;
    private Boolean checkPwd;

    public void setUserIdx(String userIdx) {
        this.userIdx = userIdx;
    }

    public void setFrIdx(String frIdx) {
        this.frIdx = frIdx;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public void setParId(String parId) {
        this.parId = parId;
    }

    public void setUserNm(String userNm) {
        this.userNm = userNm;
    }

    public void setParHp(String parHp) {
        this.parHp = parHp;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public void setUserType(String userType) {
        this.userType = userType;
    }

    public void setLoginUiType(String loginUiType) {
        this.loginUiType = loginUiType;
    }

    public void setCheckPwd(Boolean checkPwd) {
        this.checkPwd = checkPwd;
    }

 

빌더 패턴

점층적 생성자 패턴의 안정성, 자바빈즈패턴의 가독성의 장점을 모두 가지고 있는 빌더패턴으로, 연쇄적인 빌더 호출을 통해 생성하는 방식이다. 연쇄적인 호출을 플루언트 API, 메서드 연쇄라고 한다.

 

Lombok Annotation을 이용할 때 유의점이 있다. @Builder를 사용할 경우 필수 값을 가진 빌더를 만들 수 없고, 기본으로 모든 필드를 가지고 있는 생성자가 생성된다. 따라서 @AllArgsConstructor에 accessLevel을 통해 접근 제어자를 설정하여 커스텀해 주어야한다.

public class Jwt {

    private static final String SECRET_KEY = "1234"; // JWT Secret Key
    private final String userIdx;
    private final String userId;
    private final String userNm;
    private final String userType;
    private final String frIdx;
    private final String parId;
    private final String parHp;
    private final String status;
    private final String loginUiType;
    private final Boolean checkPwd;

    private Jwt(JwtBuilder jwtBuilder) {
        this.userIdx = jwtBuilder.userIdx;
        this.userId = jwtBuilder.userId;
        this.userNm = jwtBuilder.userNm;
        this.userType = jwtBuilder.userType;
        this.frIdx = jwtBuilder.frIdx;
        this.parId = jwtBuilder.parId;
        this.parHp = jwtBuilder.parHp;
        this.status = jwtBuilder.status;
        this.loginUiType = jwtBuilder.loginUiType;
        this.checkPwd = jwtBuilder.checkPwd;
        //유효성 코드 추가
    }

    public static class JwtBuilder {

        private final String userIdx;
        private final String userId;
        private final String userNm;

        private String userType;
        private String frIdx;
        private String parId;
        private String parHp;
        private String status;
        private String loginUiType;
        private Boolean checkPwd;


        public JwtBuilder(String userIdx, String userId, String userNm) {
            this.userIdx = userIdx;
            this.userId = userId;
            this.userNm = userNm;
        }

        public JwtBuilder userType(String userType) {
            this.userType = userType;
            return this;
        }

        public JwtBuilder frIdx(String frIdx) {
            this.frIdx = frIdx;
            return this;
        }

        public JwtBuilder parId(String parId) {
            this.parId = parId;
            return this;
        }

        public JwtBuilder parHp(String parHp) {
            this.parHp = parHp;
            return this;
        }

        public JwtBuilder status(String status) {
            this.status = status;
            return this;
        }

        public JwtBuilder loginUiType(String loginUiType) {
            this.loginUiType = loginUiType;
            return this;
        }

        public JwtBuilder checkPwd(Boolean checkPwd) {
            this.checkPwd = checkPwd;
            return this;
        }

        public Jwt build() {
            return new Jwt(this);
        }
    }

 

빌더 패턴 실무 적용 사례

최근 프로젝트에서 Sigle Sign On을 Json Web Token을 이용하여 처리해야 하는 일이 있었다. JWT를 복호화하여 데이터 수정 삭제 후 새롭게 암호화해야 하는 경우가 많았다. 그중 필수 값도 있었지만, 프로젝트 별 선택값 또한 무수히 많았다.

빌더 패턴으로 새롭게 리팩터링을 하였고 이로 인해 느낀 장점은 일관성은 유지하면서 수정에 용이하다였다.

//축약형 코드

Cookie[] cookies = request.getCookies();
String jwt = "";
if(cookies != null){
    for(Cookie cookie : Cookies){
      if("accessToken".equals(cookie.getName())){
      	jwt = java.net.URLDecoder.decode(cookie.getValue(), "UTF-8");
      	break;
      }
   }   
}

JwtUtil info = new JwtUtil(JwtUtil.extractAllClaims(jwt))

jwt = JwtUtil.Builder()
            .name("study")
            .build();

예제 코드

 

GitHub - VenusIM/Study_Record

Contribute to VenusIM/Study_Record development by creating an account on GitHub.

github.com

 

profile

꾸준한 스터디

@StudyRecord

포스팅이 유익하셨다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!