[OOP] 디미터의 법칙

주현·2024년 3월 31일

공부방

목록 보기
1/14

최근 김영한님 JPA강의를 보는데 도메인 모델 패턴 vs 트랜잭션 스크립트에 대해서 구글에 검색하게 되었는데, 디미터의 법칙이라는 것을 알게되었다. 이에 대해서 공부하다보니, 내가 실수했던 내용들이 전부다 적혀있었다. 그래서 이를 정리하려고 한다.


1. 디미터의 법칙

디미터 법칙은 디미터라는 프로젝트를 진행을 하는 개발자들이 어떤 객체가 다른 객체에 대해 많이 알다보니, 결합도가 높아지고 좋지 못한 설계를 야기한다는 것에 대해서 발견을 하였다. 그래서 개선하기 위해서 객체에게 자료를 숨기는 것이 아닌, 함수를 공개함. 이것을 디미터 법칙이라고 한다. 디미터 법칙은 다른 객체가 어떤 자료(필드)를 가지고 있는지 몰라야하는 의미이다. 여러개의 토트(.)을 사용하지말라는 법칙으로 많이 알려져있다. 디미터의 법칙을 준수할 시 캡슐화를 높혀 객체의 자율성과 응집도를 높일 수 있다.

객체 지향 프로그래밍에서 가장 중요하게 보는 것은 "객체가 어떤 데이터를 갖고 있냐?"가 아닌 "객체가 어떤 메세지를 주고 받냐?"이다. 그렇기에 디미터의 법칙은 객체 지향 프로그래밍에서 상당히 중요하다.

2. 디미터의 법칙 예시

[디미터의 법칙 위반 코드]

예를 들어 어떤 사용자에게 알림을 보내주는 함수를 구현한다고 합니다. 이를 구현하기 위해 User객체, Address 객체를 필요로 할 것이며, User객체는 Address라는 객체를 가지고 있을 것입니다.

@Getter
public class User{
    private String name;
    private Address address;
}

@Getter
public class Address {
    private String region;
    private String details;
}

이제 어떤 사용자가 서울에 살고 있으면 알림을 보내주는 함수를 다음과 같이 구현하였다고 하자.

@Service
public class Service{
    
    public void send(final User user){
        if("울산".equals(user.getAddress().getRegion())){
            sendNotification(user);
        }
    }
}

위의 코드는 흔하게 볼 수 있는 코드이지만, 디미터의 법칙을 위반하고 있는 코드이며 객체지향스럽지 못하다. 왜냐면 객체지향스러운 것은, 우리는 객체에게 메세지를 보내는 것인데 위 코드는 객체가 가지는 자료를 확인하고 있으며, 다른 객체가 어떠한 자료를 갖고 있는지 지나치게 잘 알기 때문이다. 우리는 Getter메소드를 통해 user객체가 name,address를 가지고 있음을 파악할 수 있다. 그렇기에 우리는 위의 코드를 객체 지향스러우며 디미터의 법칙을 준수하도록 수정할 필요가 있다.


[디미터의 법칙을 준수하는 코드]

우리는 Address 객체의 데이터를 통해 사용자의 지역을 파악하는 것이 아니라,Address의 객체에 메세지를 보내서 서울 지역에 사는지 파악하도록 구현해야한다.

public class User{
    private String name;
    private Address address;

    public boolean isUlsanUser(){
        return address.isUlsanRegion();
    }
}

public class Address {
    private String region;
    private String details;

    public boolean isUlsanRegion(){
        return "울산".equals(region);
    }
}

위와 같이 객체에게 보내는 메세지를 구현할시 @Getter 어노테이션 또한 지울 수 있고, User객체와 Address 객체가 어떠한 데이터들을 지니고 있는지 모른 채 메세지를 보낼 수 있다. 서비즈에서는 로직을 이렇게 수정 가능하다.

@Service
public class Service{
    public void send(final User user){
        if(user.isUlsanRegion()){
            sendNotification(user);
        }
    }
}

위에 작성된 코드를 보면, 기존의 user.getAddress().getRegion()처럼 여러 개의 토트(.)을 사용하여 참조하지 않기 때문에 디미터의 법칙을 잘 준수하고 있다.

DTO 나 컬렉션 객체와 같은 자료 구조의 경우에는 물을 수 밖에 없다. 만약 묻는 대상이 객체가 아닌 자료구조라면 당연히 내부를 노출해야 하므로 디미터의 법칙을 적용할 필요가 없다.

0개의 댓글