영주의 개발노트

디미터 법칙 본문

STUDY 📖/객체지향

디미터 법칙

0JUUU 2022. 2. 9. 01:54
반응형

디미터 법칙 🤔

- 디미터 법칙이란 무엇인가? 에 대해 알고 싶다면, 제가 참고한 자료 에서 확인해주세요!

 

  • 한 줄에 한 점만 있는 것을 지향하자!

디미터 법칙을 위배한 코드는 무엇일까? 🤔

자동차 경주를 구현하면서 리뷰 받은 것 중, 디미터 법칙을 위배했다고 코멘트가 달렸다. 어떠한 내용인지 살펴보자.

package racing.domain;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import racing.domain.car.Car;
import racing.domain.car.Cars;
import racing.domain.startegy.MovingStrategy;

public class RacingGame {

    private final MovingStrategy movingStrategy;
    private final Cars cars;

        // 생략

    public List<Car> getWinners() {
                final Position maxPosition = cars.findMaxPosition();
        return cars.getCars().stream()
                            .filter(car -> car.isSamePosition(maxPosition))
                            .collect(Collectors.toList());
    }
}
  • 이 코드에서 디미터 법칙을 위배한 곳을 찾아보자
    .filter(car -> car.isSamePosition(maxPosition) 이 부분이 디미터 법칙을 위배한 것

위에서 명시한 디미터 법칙의 규칙을 살펴보면

4. 인스턴스 변수로 가지고 있는 객체가 소유한 메서드 를 사용할 것을 권장한다.

현재 코드는 인스턴스 변수 멤버 변수 내부 메서드에 직접 접근하므로 디미터 법칙을 위배한다는 것을 알 수 있다.

 


그렇다면 이걸 어떻게 해결하지?

지금 문제점이 cars의 내부 멤버 변수를 다른 객체에서 직접 접근한다는 것이다.

이를 Cars 객체 내부로 로직을 이동하고 Cars를 인스턴스 변수로 갖는 클래스에서는 cars 인스턴스 변수의 메서드에 접근하면 된다.

// RacingGame.java
package racing.domain;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import racing.domain.car.Car;
import racing.domain.car.Cars;
import racing.domain.startegy.MovingStrategy;

public class RacingGame {

    private final MovingStrategy movingStrategy;
    private final Cars cars;

        // 생략

    public List<Car> getWinners() {
        return cars.decideWinners();
    }
}
package racing.domain.car;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import racing.domain.startegy.MovingStrategy;

public class Cars {

    private final List<Car> cars = new ArrayList<>();

    private Position findMaxPosition() {
        int maxPosition = 0;
        for (Car car : cars) {
            maxPosition = Math.max(maxPosition, car.getPositionValue());
        }
        return new Position(maxPosition);
    }

    public List<Car> decideWinners() {
        final Position maxPosition = findMaxPosition();
        return cars.stream()
            .filter(car -> car.isSamePosition(maxPosition))
            .collect(Collectors.toList());
    }
}

이런 식으로 RacingGame에서는 ‘Cars 내부 메서드를 사용하겠다~’ 라고만 명시해준다.

그리고, 실질적인 로직은 Cars 안에서 자신의 멤버 변수를 사용하면 된다.

이렇게 하면, RacingGame, Cars 어디에서도 디미터 법칙을 위배하지 않게 된다.

 


 

더보기

stream을 처음 접하고 나서 너무 재미있는 기능이라고 생각해서 마구잡이로 사용했던 것 같다.

그러다보니, get의 get을 하고 난리가 났었다.

자동차 경주 말고도 로또를 구현하면서 포장 객체를 많이 사용했기에 다른 곳에서 get().get() 이런게 엄청 많았어서 이에 대한 리뷰도 들어왔다.

이러한 지식을 미리 알았다면 어땠을까? 라는 생각도 하지만, 이번 기회에 알게 되어서 내 것으로 만들면 된다! 라고 생각한다!

사실, 로또를 구현하면서

  1. 기존 변수를 포장객체로 감싸거나
  2. 포장객체나 포장 객체를 인스턴스 변수로 갖는 객체 로직을 수정할 때마다
    .get().get뭐시기() 하는 부분이 에러가 났었고, 이를 다~ 고쳐줬는데 이것이 디미터법칙을 위배했기 때문에 일어났던 일이라는 것이 놀라웠다.
    고치면서 귀찮다고 생각했는데 이런게 변화에 유연하지 못한 것이라니...
    뭔가 변화에 유연하지 못해요~ 라는 말은 알았지만, 귀찮다는 감정과 변화에 유연하지 못함 이걸 귀결시키지 못했었다.

그저 그러려니.. 하는 생각을 버리고 비판적인 사고를 장착해야겠다.
불편함을 느꼈다면, 이걸 더 편하게 할 수는 없을까? 왜 불편하지? 뭔가 잘못됐나? 라고 사고하는 습관을 가질 것이다 😇

 

 

참고자료

디미터 법칙 : https://tecoble.techcourse.co.kr/post/2020-06-02-law-of-demeter/

'STUDY 📖 > 객체지향' 카테고리의 다른 글

클래스와 객체  (4) 2022.03.16