개요
이번 포스팅에서는 객체지향 프로그래밍을 위한 디미터 법칙에 대해 알아보도록 하겠습니다.
1. 디미터 법칙이란?
“다른 객체에게 내부 사정을 보여주지 말라”
저는 디미터 법칙을 위 문장으로 표현하고 싶은데요, 디미터 법칙이란 다른 객체가 어떠한 자료를 가지고 있는지, 그 내부 사정을 몰라야 한다는 것을 의미하며 Don’t talk to stranger 이라고 불리기도 합니다.
위 설명 만으로는 감이 잘 안오실 수 있는데요, 예제 코드를 통해 한 번 알아보도록 하겠습니다.
잘못된 코드의 예시입니다.
public void sendMessageForSeoulUser(final User user) {
if("서울".equals(user.getAddress().getRegion())) {
sendNotification(user);
}
}
Java
복사
위 코드를 보면 “유저는 Address 라는 필드를 가지고 있구나” 예측할 수 있게 됩니다. 즉, User 도메인의 내부 사정을 알게된 것이죠.
디미터 법칙을 적용한 올바른 코드는 어떻게 생겼을까요?
public class Address {
private String region;
private String details;
public boolean isSeoulRegion() {
return "서울".equals(region);
}
}
public class User {
private String email;
private String name;
private Address address;
public boolean isSeoulUser() {
return address.isSeoulRegion();
}
}
Java
복사
도메인 계층에 다음과 같은 코드를 작성함으로써 이전과 다른 새로운 코드를 작성할 수 있습니다.
public void sendMessageForSeoulUser(final User user) {
if(user.isSeoulUser()) {
sendNotification(user);
}
}
Java
복사
많은 분들이 착각하는 것이 있는데, . 이 많다고 해서 디미터 법칙을 위반하는 것이 아닙니다.
보통 디미터 법칙을 위반한 사례들이 앞선 코드와 같이 (user.getAddress().getRegion() ) . 을 여러 개 이어 붙여 마치 .을 많이 이어 작성하게 되면 디미터 법칙을 위반한다고 생각할 수 있는데 이는 잘못된 사실입니다.
사실 .은 Java 8에서 도입된 stream을 이용할 때 많이 사용되는데요, 중요한 건 .으로 인해 내부 구조가 외부로 유출 되는지 여부입니다. 따라서 이를 잘 판단할 필요가 있습니다.
2. 직접 디미터 법칙을 적용해보자
예제를 하나 가져왔는데요, 위 코드는 명백하게 디미터 법칙을 위반하고 있습니다.
@Service
@RequiredArgsConstructor
public class PostService {
private final PostRepository messageRepository;
public Mono<Void> deletePost(final DeletePostCommand command) {
return postRepository.findByPostId(command.getPostId())
.switchIfEmpty(Mono.error(new PostNotFoundException()))
.flatMap(post -> {
if (!post.getUser().getId().equals(command.getDeleter().getUserId())) {
return Mono.error(new AccessDeniedException());
}
return postRepository.save(post.deleteAndCopy());
})
.then();
}
}
Java
복사
바로 작성자와 삭제 요청자가 일치하는 지 확인하기 위해 여러 객체들에게 정보를 묻고 있기 때문인데요, 이를 디미터 법칙을 적용해서 어떻게 바꿀 수 있을까요?
사실 여기에 정답은 없습니다. 하지만 방법은 여러 개가 나올 수 있죠!
저라면,, 우선 작성자와 삭제 요청자의 아이디가 일치하는 건 post가 검증하도록 할 것 같습니다. 즉, 책임을 위임하는 것이죠!
public class Post {
private User user;
public Post deleteAndCopy(final PostWriter deleter){
vertifyDeletePermission(deleter);
return copyFromThis()
.deleted(true)
.build();
}
private void veriyfyDeletePermission(deleter){
if(!this.user.equals(deleter)){
throw new RuntimeException();
}
}
Java
복사