[상황]
벡엔드의 데이터를 조회하는 중에 조회된 List<VO> 형태의 데이터 중 특정 row의 VO객체를 복사하여 List에 추가하고자 하였다.
방법을 분류해 보자면 아래의 표과 같이 나뉘며 각각의 장단점이 있어보인다.
직접 복사 | 명확하고 타입 안전 | 코드가 많아짐, 유지보수 어려움 |
복사 생성자 | 캡슐화, 깔끔한 초기화 | 역시 수동 구현 필요 |
직렬화 | 구현 간단, 재사용 가능 | 성능 느림, Serializable 필요 |
라이브러리 | 코드 간단 | 외부 의존성, Serializable 필요 |
1. 직접 복사 (안전, 코드가 길어짐)
- 직접 복사는 새로운 객체를 생성하여 각각 값을 넣어주는 방식으로 안전하지만 코드가 길어지는 특징을 가지고 있다.
public class Address {
private String city;
// getters/setters
public Address deepCopy() {
Address copy = new Address();
copy.setCity(this.city); // String은 immutable이라 얕은 복사로도 괜찮음
return copy;
}
}
public class PersonVO {
private String name;
private Address address;
// getters/setters
public PersonVO deepCopy() {
PersonVO copy = new PersonVO();
copy.setName(this.name); // String은 immutable
copy.setAddress(this.address != null ? this.address.deepCopy() : null);
return copy;
}
}
2. 복사 생성자 ( 안전, 코드 길어짐)
- 직접 복사와 비슷하지만 생성자를 활용한 방식으로 캡슐화되어 안전하게 복사되지만 역시 코드가 길어진다.
public class PersonVO {
private String name;
private Address address;
public PersonVO(PersonVO other) {
this.name = other.name;
this.address = other.address != null ? new Address(other.address) : null;
}
// ...
}
3. 직렬화 ( 구현 간단, Serializable 필요 )
- 객체를 직렬화 후 역직렬화하면 객체의 깊은 복사가 된다.
public static <T extends Serializable> T deepCopy(T object) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(object);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
return (T) ois.readObject();
} catch (IOException | ClassNotFoundException e) {
throw new RuntimeException("Deep copy failed", e);
}
}
4. 라이브러리 ( 코드 간단, 라이브러리 필요)
- ObjectMapper 라이브러리가 존재한다면 사용가능하며 코드가 짧고 편하다.
import com.fasterxml.jackson.databind.ObjectMapper;
public class Main {
public static void main(String[] args) {
MemberVO original = new MemberVO("홍길동", 30, "hong@example.com");
// 깊은 복사 수행
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(original); // 객체를 JSON으로 직렬화
MemberVO copied = mapper.readValue(json, MemberVO.class); // 다시 객체로 역직렬화
compied.setEmpname("동숙이");
// 새로운 값으로 set 가능하다.
// ...
}
}
'개발지식 > BE(Back-End)' 카테고리의 다른 글
Spring Security 작동원리 (0) | 2023.04.03 |
---|---|
RestAPI란? (0) | 2023.04.02 |
Spring Framework - Handler란? (0) | 2023.04.01 |
Spring Framework - Repository의 역할 (0) | 2023.04.01 |
Spring Framework - Controller와 RestController의 차이 (0) | 2023.04.01 |