공부/자바

[자바] 디미터의 법칙, getter를 잘 쓰기

ghhong 2023. 1. 16. 16:34

디미터의 법칙(Law of Demeter)

디미터의 법칙은 Demeter라는 프로젝트를 진행하던 개발자들이 어떤 객체가 다른 객체에 대해 지나치게 많이 알기 때문에 결합도가 높고 좋지 못한 설계를 야기한다는 것을 발견하였다. 이를 개선하고자 객체에 자료(상태값) 숨기고 함수를 공개한다. 이것이 디미터의 법칙이다. , 다른 객체가 어떤 자료(상태값) 갖고 있는지 몰라야 한다는 것이다.

= don’t talk to strangers(낯선 이에게 말하지 마라) , principle of least knowledge(최소 지식 원칙) 알려져있다. 또는 직관적으로 이해하기 위해 여러 개의 .(도트) 사용하지 말라고도 알려져 있다.

디미터의 법칙을 준수하면 캡슐화를 높여 응집도를 높일 있다.

 

OOP에서의 디미터의 법칙

객체가 어떤 데이터를 갖고 있는지보다 객체가 어떤 메시지를 주고받는가에 집중한다.

디미터의 법칙 위반 사례

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

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

 

출처: <https://mangkyu.tistory.com/147>

 

위와 같이 작성된 클래스들이 있고.

User로부터 region 찾는다고 한다면

@Service public class NotificationService

{ public void sendMessageForSeoulUser(final User user)

{ if("서울".equals(user.getAddress().getRegion()))

{ sendNotification(user); } } }

 

출처: <https://mangkyu.tistory.com/147>

 

이렇게 있다.

객체에게 메시지를 보내는 것이 아니라 객체가 가지는 자료를 확인하고 있다. 디미터의 법칙을 위반하고 있다. Getter메서드를 통해 email, name, address 등을 갖고 있음을 있다.

 

디미터의 법칙 준수 사례

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(); } }

 

출처: <https://mangkyu.tistory.com/147>

 

위와 같이 구현한 뒤에

@Service public class NotificationService

{ public void sendMessageForSeoulUser(final User user)

{ if(user.isSeoulUser()) { sendNotification(user); } } }

 

출처: <https://mangkyu.tistory.com/147>

 

메시지를 보내서 로직을 수행한다.

여러 개의 도트를 사용하지 않고, 객체 내부 구조가 외부로 노출되지 않는다.

 

 

getter, setter

자바 설계 규약에 따라 게터세터를 사용한다. 상태값은 private 작성하여 외부에서 접근할 없게하고 메서드만 노출시킨다. 위에서 말했듯이 객체에게 메시지를 보내 객체 스스로 일을 하도록 해야한다. 그것이 OOP이니까.

모든 멤버변수에 getter 생성해놓고 상태값을 꺼내쓰면 객체가 일하는 것이 아니고 메시지를 주고받는 것도 아니다. 특히 외부에서 상태값을 변경할 있는 위험도 생긴다.

 

Getter메서드를 사용하지 않고 메시지를 보내 객체가 일하도록 해보면

 

public class Car implements Comparable<Car> {
        
...
   
public boolean isSamePosition(Car other) {
       
return other.position == this.position;
         
}
         
   
@Override
   
public int compareTo(Car other) {
       
return this.position - other.position;
   
}
        
...
}

public class Cars {
        
...
   
public List<String> findWinners() {
       
final Car maxPositionCar = findMaxPositionCar();
       
return findSamePositionCars(maxPositionCar);
   
}
   
   
private Car findMaxPositionCar() {
       
Car maxPositionCar = cars.stream()
           
.max(Car::compareTo)
           
.orElseThrow(() -> new IllegalArgumentException("차량 리스트가 비었습니다."));
   
}

private List<String> findSamePositionCar(Car maxPositionCar) {
       
return cars.stream()
           
.filter(maxPositionCar::isSamePosition)
           
.map(Car::getName)
           
.collect(Collectors.toList());
   
}
}

 

출처: <https://tecoble.techcourse.co.kr/post/2020-04-28-ask-instead-of-getter/>

(가장 빠른 자동차 구하기 코드)

Comparable 상속받아 compareTo() 구현하여 비교하도록 한다.

 

박재성님은 이렇게 말했다고 한다

상태를 가지는 객체를 추가했다면 객체가 제대로 된 역할을 하도록 구현해야 한다.
객체가 로직을 구현하도록 해야한다.
상태 데이터를 꺼내 로직을 처리하도록 구현하지 말고 객체에 메시지를 보내 일을 하도록 리팩토링한다.

 

출처: <https://tecoble.techcourse.co.kr/post/2020-04-28-ask-instead-of-getter/>

 

Getter 무조건 사용하지 말라는 말이 아니다. 출력을 위한 순수값 프로퍼티를 가져오기 위해서는 사용해도 된다. 그러나 Collection인터페이스는 외부에서 getter 얻은 주소를 통해 상태값을 변경시킬 있으니 Collections.unmodifieableList처럼 unmodifiable Collection 사용하여 외부에서 변경할 없게 한다.

 

public List<Car> getCars() {
                
return cars;
        
} (x)

public List<Car> getCars() {
                
return Collections.unmodifiableList(cars);
        
} (o)

 

출처: <https://tecoble.techcourse.co.kr/post/2020-04-28-ask-instead-of-getter/>

 


출처 : https://mangkyu.tistory.com/147

 

[OOP] 디미터의 법칙(Law of Demeter)

1. 디미터의 법칙(Law of Demeter) [ 디미터의 법칙(Law of Demeter) 이란? ] 디미터의 법칙은 “Object-Oriented Programming: An Objective Sense of Style” 에서 처음으로 소개되었다. Demeter라는 프로젝트를 진행하던 개

mangkyu.tistory.com

https://tecoble.techcourse.co.kr/post/2020-04-28-ask-instead-of-getter/

 

getter를 사용하는 대신 객체에 메시지를 보내자

getter는 멤버변수의 값을 호출하는 메소드이고, setter는 멤버변수의 값을 변경시키는 메소드이다. 자바 빈 설계 규약에 따르면 자바 빈 클래스 설계 시, 클래스의 멤버변수의 접근제어자는 private

tecoble.techcourse.co.kr