티스토리 뷰

기타

디미터의 법칙

GiHoo 2023. 10. 6. 23:05

도서관 관리 프로그램 과제에 대한 코드 리뷰를 받았는데 아래의 코드에 멘토님께서 이런 말씀을 해주셨습니다.

코드 리뷰 내용

 

디미터의 법칙을 듣고 "SOLID와 같은 객체지향적인 코드를 위한 또다른 방법인가?" 라고 생각했었는데 알아보니

디미터의 법칙은 다른 객체가 어떠한 자료를 갖고 있는지 속사정을 몰라야 한다 라는 의미입니다.

이해 하기 쉽게 여러 개의 .(도트)를 사용하지 말자 라고 말하기도 합니다.

 

한 번 코드로 예시를 들어보겠습니다.

아래는 과제에서 사용한 Book 객체와 Repository 클래스의 findByTitleContaining 메서드입니다.

@Getter
public class Book {
    private int id;
    private String title;
    private String author;
    private int page;
    private String condition;

    public Book(int id, String title, String author, int page, String condition) {
        this.id = id;
        this.title = title;
        this.author = author;
        this.page = page;
        this.condition = condition;
    }
}



Repository 클래스

public List<Book> findByTitleContaining(String searchTitle, List<Book> bookList) {
        return bookList.stream()
                .filter(book -> book.getTitle().contains(searchTitle))
                .map(book -> new Book(book.getId(), book.getTitle(), book.getAuthor(), book.getPage(), book.getCondition()))
                .toList();
}

메서드의 .filter(book -> book.getTitle().contains(searchTitle)) 코드를 보면 위에서 말한 디미터의 법칙이 무엇인지 알 수 있습니다.

book 객체의 필드 값을 getter로 가져온 뒤 그 값을 통해 contains로 비교하고 있습니다.

이는 메서드가 다른 객체의 자료를 알게 되는 것이므로 디미터의 법칙을 위반한 것 입니다.

 

book 객체의 내부 사정을 알지 않고 비교하려면(사용하려면) book 객체에게 메세지를 보내는 방법을 적용해보는 것이 좋습니다.

@Getter
public class Book {
    private int id;
    private String title;
    private String author;
    private int page;
    private String condition;

    public Book(int id, String title, String author, int page, String condition) {
        this.id = id;
        this.title = title;
        this.author = author;
        this.page = page;
        this.condition = condition;
    }

    public boolean isTitleContaining(Book book, String searchTitle) {
        return book.getTitle().toLowerCase().contains(searchTitle.toLowerCase());
    }
}

Repository 클래스

public List<Book> findByTitleContaining(String searchTitle, List<Book> bookList) {
        return bookList.stream()
                .filter(book -> book.isTitleContaining(book, searchTitle))
                .map(book -> new Book(book.getId(), book.getTitle(), book.getAuthor(), book.getPage(), book.getCondition()))
                .toList();
}

위 코드를 보면 Repository 클래스에서 book 객체 내부 필드를 조회하는 것이 아닌

book 객체에게 메세지를 보내 Title을 포함하는지 물어보고, 그 결과로 작업을 수행하는 것 입니다.

 

직접 객체에 접근하기보다는 객체에 메세지를 보내 물어보는 것 

이 방식을 통해 우리는 디미터의 법칙을 지킬 수 있을 것 입니다.

 

 

번외) Stream은 디미터의 법칙을 위반하지 않는가??

처음 디미터의 법칙을 알게 되었을 때 궁금했던 것이 있었습니다.

Stream은 디미터의 법칙을 지키고 있는 것인가? 였습니다.

디미터의 법칙이 여러 개의 .(도트)를 사용하지 말자 라고도 하기 때문에 이렇게 생각했었습니다.

 

삽질을 해본 결과

디미터의 법칙은 다른 객체가 어떠한 자료를 갖고 있는지 속사정을 몰라야 한다 라는 의미입니다.

도트는 이해하기 쉽게 하려고 한 것이고

스트림의 경우에는 여러 개의 .(도트)를 사용하고 있지만, 디미터의 법칙을 위배하는 코드가 아닙니다.

객체의 내부 구조가 외부로 노출되는지에 대한 것이 주안점이며

Stream 경우에는 동일한 Stream으로 변환하여 반환 할 뿐, 캡슐화는 그대로 유지되므로 문제가 없는 것 입니다.

여러 도트를 사용하더라도 객체의 내부 구현이 노출되지 않는다면 그것은 디미터의 법칙을 준수하는 코드임을 알 수 있었습니다.

 

 

 

 

공지사항
최근에 올라온 글
최근에 달린 댓글
«   2024/09   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30