Spring 프레임워크에서 Controller, Service, Repository를 사용하는 상황에서 "Tell, Don't Ask" 원칙을 잘 지킨 예시와 잘 지키지 못한 예시를 보여드리겠습니다. 이 예시들은 사용자 정보를 업데이트하는 기능을 가정합니다.
1. 원칙을 잘 지키지 못한 예시
//Repository
@Repository
public class UserRepository {
// ... 데이터베이스 접근 메소드들
public User findById(Long id) {
// 데이터베이스에서 ID로 사용자 찾기
}
}
//Service
@Service
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public void updateUser(Long userId, UserDto userDto) {
User user = userRepository.findById(userId);
if (user != null) {
user.setName(userDto.getName()); // 직접 상태 변경
user.setEmail(userDto.getEmail()); // 직접 상태 변경
// 다른 필드도 마찬가지로 직접 변경
userRepository.save(user);
}
}
}
//Controller
@RestController
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@PutMapping("/users/{id}")
public ResponseEntity<?> updateUser(@PathVariable Long id, @RequestBody UserDto userDto) {
userService.updateUser(id, userDto);
return ResponseEntity.ok().build();
}
}
문제점: UserService에서 User 객체의 상태를 직접 변경합니다. 이는 객체의 캡슐화를 침해하고, 객체의 상태 변경 로직이 여러 곳에 흩어져 있을 수 있습니다.
2. 원칙을 잘 적용한 예시
///Repository
@Repository
public class UserRepository {
// ... 데이터베이스 접근 메소드들
public User findById(Long id) {
// 데이터베이스에서 ID로 사용자 찾기
}
}
//Service
@Service
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public void updateUser(Long userId, UserDto userDto) {
User user = userRepository.findById(userId);
if (user != null) {
user.updateDetails(userDto); // Tell, Don't Ask 원칙 적용
userRepository.save(user);
}
}
}
// User 엔티티 내부에 추가된 메소드
class User {
// ... 기존 필드와 메소드
public void updateDetails(UserDto userDto) {
this.name = userDto.getName();
this.email = userDto.getEmail();
// 다른 필드도 마찬가지로 업데이트
}
}
//Controller
@RestController
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@PutMapping("/users/{id}")
public ResponseEntity<?> updateUser(@PathVariable Long id, @RequestBody UserDto userDto) {
userService.updateUser(id, userDto);
return ResponseEntity.ok().build();
}
}
적용 방식: UserService는 User 객체에게 상태를 업데이트할 것을 요청합니다(user.updateDetails(userDto)). 이를 통해 User 객체의 캡슐화가 유지되고, 모든 상태 변경 로직이 User 내부에 존재하게 됩니다.
장점: 이렇게 하면 User 객체의 내부 구현이 바뀌어도 UserService를 수정할 필요가 없습니다. 이는 코드의 유지보수성과 확장성을 향상시킵니다.
요약
잘못된 예시에서는 UserService가 User 객체의 상태를 직접 변경합니다.
잘된 예시에서는 UserService가 User 객체에게 상태 변경을 요청합니다(Tell, Don't Ask 원칙). 이로 인해 객체의 캡슐화가 유지되고, 코드의 유지보수성이 개선됩니다.
'메모장' 카테고리의 다른 글
예외 래핑 예시 (0) | 2023.12.05 |
---|---|
law of demeter, tell don't ask 지키기 위한 공식 (0) | 2023.12.05 |
의존 역전 원칙 (0) | 2023.12.05 |
RequestPart, RequestBody 같이 못씀 (0) | 2023.12.04 |
포스트맨 파일 보내기 (0) | 2023.12.04 |