필수가 아닌 선택적인 매개변수가 많을때 정적 팩터리와 생성자로 대응하기 쉽지 않다는 점이다.
점층적 생성자 패턴
- 선택 값을 하나씩 추가하여 생성자를 점층적으로 만드는 패턴이다.
매개변수의 개수나 타입이 일치하지 않을 경우 컴파일 오류를 통해 누락된 값을 확인할 수 있는 안전성을 가지고 있다.
그러나, 적당한 개수의 매개변수에 대한 점층적 생성자 패턴은 괜찮아 보일지 몰라도 점점 많아지는 생성자로 클래스 코드의 추가 수정 삭제등 유지보수에 대한 불편함이 있다. 또한 각 생성자의 의미, 어떠한 매개변수가 들어가야 하는지에 대한 가독성이 떨어진다..
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();
예제 코드
'Effective Java > 정리' 카테고리의 다른 글
아이템6 불필요한 객체 생성을 피하라 (0) | 2023.01.08 |
---|---|
아이템5 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라 (0) | 2023.01.08 |
아이템 4 인스턴스화를 막으려거든 private 생성자를 사용하라 (0) | 2023.01.08 |
[Item 3] private 생성자나 열거 타입으로 싱글턴임을 보증하라 (0) | 2023.01.07 |
[Item 1] 생성자 대신 정적 팩터리 메서드를 고려하라 (0) | 2023.01.04 |