이번 글은 어떤 지식을 전하는 글이라기 보단, 프로젝트를 하면서 제가 놓치고 있었던 부분에 대한 회고록에 가깝습니다,,ㅎㅎ
멘토님의 피드백을 받고 느끼게 된 것은 '내가 정말 자바의 상속을 이용하지 못하고 있구나'입니다.
제가 자바를 좋아하는 이유는 객체지향을 잘 지원해주는 언어이기 때문이라고 생각했는데, 정작 프로젝트를 하면서 상속을 거의 이용하지 않고 있었다는 것이 부끄러워졌습니다.
멘토님께서 피드백 주신 것이, 일단 응답 객체인 FailureResult
, SuccessResult
가 상속 구조로 변경할 수 있을 것 같으니 이 둘을 상속 구조로 바꿔보라는 것이었습니다.
오늘 포스트는 이 두 객체를 상속 구조로 바꾸는 일종의 리팩토링(?) 과정에 대해 기록해보려고 합니다.
원래는 어떻게 되어 있었는데?
원래 코드는 아래와 같습니다.
FailureResult.java
package com.mewsinsa.global.response;
public class FailureResult {
private DetailedStatus status;
private String code;
private String message;
//==Constructor==//
// builder를 통해서만 생성되도록 private으로 정의
private FailureResult(Builder builder) {
this.status = builder.status;
this.code = builder.code;
this.message = builder.message;
}
//==Getter==//
public DetailedStatus getStatus() {
return status;
}
public String getMessage() {
return message;
}
public String getCode() {
return code;
}
//==Builder==//
public static class Builder {
DetailedStatus status;
String code;
String message;
public Builder() {
}
public Builder status(DetailedStatus status) {
this.status = status;
return this;
}
public Builder message(String message) {
this.message = message;
return this;
}
public Builder code(String code) {
this.code = code;
return this;
}
public FailureResult build() {
return new FailureResult(this);
}
}
}
SuccessResult.java
package com.mewsinsa.global.response;
public class FailureResult {
private DetailedStatus status;
private String code;
private String message;
//==Constructor==//
// builder를 통해서만 생성되도록 private으로 정의
private FailureResult(Builder builder) {
this.status = builder.status;
this.code = builder.code;
this.message = builder.message;
}
//==Getter==//
public DetailedStatus getStatus() {
return status;
}
public String getMessage() {
return message;
}
public String getCode() {
return code;
}
//==Builder==//
public static class Builder {
DetailedStatus status;
String code;
String message;
public Builder() {
}
public Builder status(DetailedStatus status) {
this.status = status;
return this;
}
public Builder message(String message) {
this.message = message;
return this;
}
public Builder code(String code) {
this.code = code;
return this;
}
public FailureResult build() {
return new FailureResult(this);
}
}
}
코드가 엄청 긴건 그냥 롬복 안써서 그래요.. 아마도.. 일부러 안쓴거예요
변수 선언 부분만 보시면
이렇게 노란색 박스로 표시된 부분이 겹친다는 것을 확인하실 수 있습니다.
이 겹치는 부분을 부모 클래스인 FailureResult
에 넣어두고 자식 클래스인 SuccessResult
에는 data
필드만 남기려고 합니다.
또한 위에 사진에서는 SuccessResult
에는 code
라는 필드가 없지만 상속 구조로 바꾸면서 SuccessResult
에도 code가 추가되도록 수정할 예정입니다.
즉 제가 수정하려고 하는 내용을 정리하면 아래와 같습니다.
고치는 과정
FailureResult
를 부모 클래스로 할 것이므로 이름을ResponseResult
로 변경해줍니다. (Success가 Failure를 상속 받는 것은 의미상 이상하니까..)ResponseResult
에는status
,code
message
필드를 남기고 이 필드의 접근제어자를 모두protected
로 변경해줍니다. (자식 클래스에서 접근할 수 있도록)message
필드는 상황에 따라 응답 값에 포함될 수도, 아닐 수도 있기 때문에@JsonInclude(Include.NON_NULL)
어노테이션을 붙여줍니다.ResponseResult
에 매개변수가 없는 생성자를 만들어주고 접근제어자를protected
로 설정해줍니다. (자식 클래스에서super()
를 호출할 수 있도록)SuccessResult
가ResponseResult
를 상속 받도록 합니다.SuccessResult
에는data
필드만 남기고, 상황에 따라 응답 데이터가 없을 수도 있으므로@JsonInclude(Include.NON_NULL)
를 붙여줍니다.
결과물
위와 같은 과정을 거쳐서 수정한 두 클래스는 아래와 같습니다.
ResponseResult.java
package com.mewsinsa.global.response;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
public class ResponseResult {
protected DetailedStatus status;
protected String code;
@JsonInclude(Include.NON_NULL)
protected String message;
//==Constructor==//
// builder를 통해서만 생성되도록 private으로 정의
protected ResponseResult(Builder builder) {
this.status = builder.status;
this.code = builder.code;
this.message = builder.message;
}
protected ResponseResult() {
}
//==Getter==//
public DetailedStatus getStatus() {
return status;
}
public String getMessage() {
return message;
}
public String getCode() {
return code;
}
//==Builder==//
public static class Builder {
DetailedStatus status;
String code;
String message;
public Builder() {
}
public Builder status(DetailedStatus status) {
this.status = status;
return this;
}
public Builder message(String message) {
this.message = message;
return this;
}
public Builder code(String code) {
this.code = code;
return this;
}
public ResponseResult build() {
return new ResponseResult(this);
}
}
}
SucceessResult.java
package com.mewsinsa.global.response;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import org.springframework.web.bind.MethodArgumentNotValidException;
public class SuccessResult extends ResponseResult {
@JsonInclude(Include.NON_NULL)
private Object data;
//==Constructor==//
// builder를 통해서만 생성되도록 private으로 정의
protected SuccessResult(Builder builder) {
this.status = builder.status;
this.code = builder.code;
this.message = builder.message;
this.data = builder.data;
}
//==Getter==//
public DetailedStatus getHttpStatus() {
return status;
}
public String getMessage() {
return message;
}
public Object getData() {
return data;
}
//==Builder==//
public static class Builder {
DetailedStatus status;
String message;
String code;
Object data;
// httpStatus에 대한 정보는 반드시 필요
public Builder(DetailedStatus status) {
this.status = status;
}
public Builder message(String message) {
this.message = message;
return this;
}
public Builder data(Object data) {
this.data = data;
return this;
}
public Builder code(String code) {
this.code = code;
return this;
}
public SuccessResult build() {
return new SuccessResult(this);
}
}
}
좋은 구조로 잘 고친 것인지는 잘 모르겠습니다,,
아무래도 내부에 static class로 구현되어있는 Builder는 상속을 쓰지 않고 두 클래스에 모두 하드코딩되어있는 상황이긴한데
아무튼 ResponseResult
와 SuccessResult
는 상속 관계로 바꾸어주었으니, 조금은 더 자바의 객체 지향을 잘 이용한 코드로 발전하지 않았을까..?하는 생각입니다.
솔직히 말하면, 이미 저 응답 객체들을 Controller 여기저기서 많이 쓴 상태라, 클래스 한번 고치면 몇십 줄의 코드를 더 고쳐야하는 상황에 놓일 수 있어서 조심스러워서 많이 고치지는 못했습니다.
하지만 더 개선할 부분이 있는지 고민해보고, 시간 여유가 될때 바뀐 클래스 구조에 맞게 컨트롤러 코드들도 수정해야겠습니다.
'프로젝트 기록 > Spring' 카테고리의 다른 글
[Spring Data JPA] MariaDB에서의 동시성 이슈로 인한 갱신 이상 문제와 그 해결법(비관적 락, 낙관적 락) (2) | 2024.11.20 |
---|---|
[Spring / FCM] FCM 웹 푸시 알림 구현기 (서버 편) (6) | 2024.09.22 |
[Spring / Redis] 이중화 서버에서의 웹 소켓 채팅 + SSE 알림 구현기 (11) | 2024.09.07 |
[Spring / Redis] @RedisHash 어노테이션을 붙인 객체를 레디스에 저장했을때, 그 값을 확인하는 방법 (0) | 2024.05.18 |