꾸준한 스터디
article thumbnail

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

 

1. 점층적 생성자 패턴

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

 

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

 

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

<java />
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; }

 

2. 자바 빈즈 패턴

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

 

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

 

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

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

<java />
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; }

 

3. 빌더 패턴

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

 

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

<java />
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); } }

 

4. 빌더 패턴 실무 적용 사례

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

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

<java />
//축약형 코드 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();

5. 예제 코드

 

GitHub - VenusIM/Study_Record

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

github.com

 

profile

꾸준한 스터디

@StudyRecord

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