일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- programmers
- CJ UNIT
- C++
- 자바
- 백준
- 1과목
- 코딩교육봉사
- 코틀린
- SW봉사
- 시나공
- kotlin
- BFS
- java
- MYSQL
- 백준알고리즘
- 프로그래머스
- 파이썬
- SQL
- softeer
- 백준 알고리즘
- 스프링
- 공부일지
- 코딩봉사
- 알고리즘
- 데이터베이스
- 회고
- python
- 소프티어
- 정보처리산업기사
- 문제풀이
- Today
- Total
JIE0025
DTO에서 추상클래스를 사용하는것에 대하여 본문
DTO를 생성하는 방법은 2가지가 있다.
1. 모든 요청/응답에 대한 파일을 분리하여 생성하는 방법
2. 한개의 파일을 정의하고, 내부클래스로 생성하는 방법
오늘 이야기할 DTO에서 추상클래스를 정의하는 것은
2번 한개의 파일을 정의하고, 내부클래스로 생성하는 방법에서 해당되는 이야기이니 참고 바란다))
✅ 개요
장소(Amenity) 데이터의 입력이 게시글(BulletinPost)작성시 Body로 들어오도록 설계되었다.
따라서 입력 데이터 역시 BulletinPostDto내부에 들어오게 되는데,
이때 Create와 Patch 클래스의 내부 필드가 유사함에 따라 DTO에 추상클래스를 만들어보는것에 대한 쟁점이 생겼다.
⏺ 원래 DTO
public class BulletinPostDto {
private static BulletinPostService bulletinPostService;
public BulletinPostDto(BulletinPostService bulletinPostService) {
this.bulletinPostService = bulletinPostService;
}
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public static class Create {
private String postContent;
private long addressId;
private String amenityName;
private String address;
private double longitude;
private double latitude;
}
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public static class Patch {
private long bulletinPostId;
private String postContent;
private long addressId;
private String amenityName;
private String address;
private double longitude;
private double latitude;
}
}
📣 왜 추상클래스로 묶고자 했나?
위의 코드를 보면 Create 클래스와 Patch 클래스의 필드와 생성자가 서로 너무나 유사함을 볼 수 있다.
클래스가 다르다는 이유만으로 Mapper부분의 코드가 달라지고, 추가적인 중복 코드가 생성되는것을 방지하기 위해
추상클래스를 만들고자 했다.
⏺ 추상클래스를 적용한 DTO
1. 공통되는 필드를 추상클래스에 묶는다.
2. 해당 필드들을 모두 포함하는 생성자를 만든다
3. 공통된것을 묶었으므로, Create, Patch클래스가 추상클래스를 상속하도록 한다.
4. 생성자 호출시 추상클래스의 생성자를 호출하도록 한다.
public class BulletinPostDto {
@Getter
public static abstract class InnerParent {
private String postContent;
private long addressId;
private String amenityName;
private String address;
private double longitude;
private double latitude;
public InnerParent(String postContent, long addressId, String amenityName, String address, double longitude, double latitude) {
this.postContent = postContent;
this.addressId = addressId;
this.amenityName = amenityName;
this.address = address;
this.longitude = longitude;
this.latitude = latitude;
}
}
@Getter
@Setter
public static class Create extends InnerParent {
public Create(String postContent, long addressId, String amenityName, String address, double longitude, double latitude) {
super(postContent, addressId, amenityName, address, longitude, latitude);
}
}
@Getter
@Setter
public static class Patch extends InnerParent {
private long bulletinPostId;
@Builder
public Patch(String postContent, long addressId, String amenityName, String address, double longitude, double latitude) {
super(postContent, addressId, amenityName, address, longitude, latitude);
}
}
}
⏺ 무엇이 개선되었고 무엇이 문제일까?
👍 개선된 점 : 기대한 바와 같이 코드의 중복을 없앴다.
1) Entity에서 Dto로 변환하는 mapper 호출시 create/patch 클래스가 달라서
메서드가 분리되었었는데 , 똑같은 추상클래스를 상속받으면서 한개의 메서드로 매퍼를 호출할 수 있다.
//변경 이전
amenityMapper.bulletinPostCreateDtoToAmenityCreateDto(bulletinPostCreateDto);
//변경 이후
amenityMapper.bulletinPostDtoToAmenityCreateDto(bulletinPostPatchDto);
Mapper 코드의 중복 제거
@Mapper(componentModel = "Spring")
public interface AmenityMapper {
Amenity amenityCreateDtoToAmenity(AmenityCreateDto amenityCreateDto);
AmenityResponseDto amenityToAmenityResponseDto(Amenity amenity);
List<AmenityResponseDto> AmenityListToAmenityResponseDto(List<Amenity> amenityList);
default <T extends BulletinPostDto.InnerParent> AmenityCreateDto bulletinPostDtoToAmenityCreateDto(T bulletinPostDto) {
if ( bulletinPostDto == null ) {
return null;
}
AmenityCreateDto amenityCreateDto = AmenityCreateDto
.builder()
.addressId(bulletinPostDto.getAddressId())
.amenityName(bulletinPostDto.getAmenityName())
.address(bulletinPostDto.getAddress())
.longitude(bulletinPostDto.getLongitude())
.latitude(bulletinPostDto.getLongitude())
.build();
return amenityCreateDto;
}
}
Create호출과 Patch 호출부분이 달랐는데, 똑같은 추상클래스를 이용함으로써, 한개의 메서드만으로 처리가 가능해진다.
👍 쟁점 : 가독성 면에서 좋은걸까?
공통 데이터를 추상화하고 묶는것이 항상 좋은것인지에 대해선 고민해봐야한다.
추상클래스를 사용함으로써 얻는 장점이 과연 DTO에도 적용되는걸까?
코드의 재사용성은 분명히 높혔지만 DTO라는 데이터를 이동시키는 역할에서, 추상클래스를 한번 더 찾아가야만 필드를 정확히 알 수 있다는것은 단점이 될 수도 있다.
추가적으로 기존의 존재하던 생성과 수정 DTO를 제외하고, 해당 추상클래스를 상속받을 것이 더 없다는 점도 고려해보자.
딱 2번만 사용될 코드를 굳이 추상화하여 재사용하는것보다는
어떤 데이터가 필요한지 한눈에 볼 수 있는 코드 가독성을 높히는게 더 합리적인 선택일 수 있다.
이런저런 고민을 했지만
결국 설계상 이슈로 게시글 수정시에도 POST mapping 을 사용하게 되면서......
DTO역시 Create만 필요하고 PatchDTO를 사용하지 않게 되어,
추상클래스 자체의 의미가 없어져버렸다🥲
좋은 경험이었다고 생각하고 마무리!