back-end-study / effective-java

🔥 이펙티브 자바 스터디
43 stars 4 forks source link

[Item14] p89 Comparable을 구현한 클래스를 확장해 값 컴포넌트를 추가하는경우 #23

Open youngreal opened 2 years ago

youngreal commented 2 years ago
  1. 실용성이 어느정도로 있는이야기인지 잘 모르겠지만 Comparable을 구현한 클래스를 확장해 값컴포넌트를 추가하신 경험이 있으신지 없으시다면 어떻게 생각하시는지 궁금합니다

  2. 위의 내용에 이어 이 클래스에 원래 클래스의 인스턴스를 가리키는 필드를두자. 그런다음 내부 인스턴스를 반환하는'뷰 메서드를 제공한다 라는부분이 자꾸 물음표가 생깁니다 ㅠ 도와주세요

jun108059 commented 2 years ago
  1. 실용성이 어느정도로 있는이야기인지 잘 모르겠지만 Comparable을 구현한 클래스를 확장해 값컴포넌트를 추가하신 경험이 있으신지 없으시다면 어떻게 생각하시는지 궁금합니다

설명해주신 내용의 경험은 없지만, 책의 내용을 인용하면 구체 클래스에서 새로운 값 컴포넌트를 추가하면 compareTo 규약을 지킬 방법이 없다는 문구를 보니 꼭 필요하다면, 우회하는 방법을 사용해 아래 예제 코드처럼 구현하면 좋을 것 같습니다.

  1. 위의 내용에 이어 이 클래스에 원래 클래스의 인스턴스를 가리키는 필드를두자. 그런다음 내부 인스턴스를 반환하는'뷰 메서드를 제공한다 라는부분이 자꾸 물음표가 생깁니다 ㅠ 도와주세요

책에서 설명한 대로, 객체 지향적 추상화의 이점을 포기하고 '뷰' 메서드를 제공하면 아래와 같은 코드를 작성할 수 있습니다.

Point 클래스

class Point implements Comparable<Point> {
    private int x;
    private int y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public int compareTo(Point point) {
        int result = Integer.compare(x, point.x);
        if (result == 0) {
            return Integer.compare(y, point.y);
        }
        return result;
    }
}

NamedPoint 클래스

class NamedPoint implements Comparable<NamedPoint> {
    // 원래 클래스의 인스턴스를 가르키는 필드
    private Point point;

    private String name;

    public NamedPoint(Point point, String name) {
        this.point = point;
        this.name = name;
    }
    // 내부 인스턴스를 반환하는 '뷰' 메서드
    public Point viewPoint() {
        return point;
    }

    @Override
    public int compareTo(NamedPoint namePoint) {
        int result = point.compareTo(namePoint.point);
        if (result == 0) {
            return name.compareTo(namePoint.name);
        }
        return result;
    }
}

이렇게 하면 NamedPoint 클래스에 원하는 compareTo 메서드를 새롭게 구현할 수 있게 되어 구체 클래스 Point에서 compareTo 일반 규약을 지킬 수 있게 됩니다.

Test 코드로 검증하면 아래와 같습니다.

class PointTest {

    @DisplayName("compareTo의 일반 규약을 지킬 수 있다")
    @Test
    void test() {
        Point point = new Point(1, 3);
        NamedPoint namedPoint = new NamedPoint(new Point(1, 2), "food");

        assertThat(point.compareTo(namedPoint.viewPoint())).isEqualTo(1);
        assertThat(namedPoint.viewPoint().compareTo(point)).isEqualTo(-1);
    }

}