public class SignupRequest {
// ...
@Pattern(regexp = "^.{8,}$", message = "비밀번호는 8글자 이상이어야 합니다")
private String password;
// ...
}
@RestController
public class MemberController {
// ...
@PostMapping
public ResponseEntity<MemberSignupResponse> signup(@Valid @RequestBody MemberSignupRequest request) {
MemberSignupResponse response = memberService.register(request);
return ResponseEntity.ok().body(response);
}
}
위와 같은 코드가 있을 때,
public class ChangePasswordRequest {
private String oldPassword;
// NOTE 중복 코드
@Pattern(regexp = "^.{8,}$", message = "비밀번호는 8글자 이상이어야 합니다")
private String newPassword;
public ChangePasswordRequest(String oldPassword, String newPassword) {
this.oldPassword = oldPassword;
this.newPassword = newPassword;
}
}
@RestController
public class MemberController {
// ...
@PutMapping("/{id}/password")
public ResponseEntity<ChangePasswordRequest> changePassword(@MemberId String loginId,
@PathVariable String id, @Valid @RequestBody ChangePasswordRequest request) {
memberService.changePassword(loginId, id, request);
return ResponseEntity.noContent().build();
}
}
이렇게 비밀번호를 변경하는 api를 추가하려고 하니,
@Pattern(regexp = "^.{8,}$", message = "비밀번호는 8글자 이상이어야 합니다")
라는 중복 코드가 발생하게 되었다.
@Embeddable
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Password {
private static final String REGEX = "^.{8,}$";
private String value;
public Password(String value) {
validate(value);
this.value = value;
}
private void validate(String value) {
if (!Pattern.matches(REGEX, value)) {
throw new PasswordPatternNotMatchException();
}
}
}
@Entity
public class Member {
// ...
private Password password;
// ...
public Member(/*...,*/ String password /*,...*/) {
// ...
this.password = new Password(password);
// ...
}
public void changePassword(String oldPassword, String newPassword) {
checkPasswordMatch(oldPassword);
this.password = new Password(newPassword);
}
}
@Service
public class MemberService {
public void changePassword(String loginId, String id, ChangePasswordRequest request) {
if (!Objects.equals(loginId, id)) {
throw new UnauthorizedException();
}
Member member = findById(IdFactory.createMemberId(id));
member.changePassword(request.getOldPassword(), request.getNewPassword());
}
}
Password 는 Value이므로 setter가 없어서 member.password를 변경하려면 무조건 Password 인스턴스를 생성해야 하고, 생성자에서 검증이 이뤄지므로 모든 비밀번호 변경 로직은 검증을 거치게 된다.
이로써 비밀번호 형식이 변경되면 도메인의 REGEX 상수만 수정하면 된다!