[이펙티브 자바] 아이템 23. 태그 달린 클래스보다는 클래스 계층구조를 활용하라

June·2022년 3월 19일
0

[이펙티브자바]

목록 보기
22/72
public class Figure {
    enum Shape {RECTANGLE, CIRCLE};

    // 태그 필드 - 현재 모양을 나타낸다.
    final Shape shape;

    // 다음 필드들은 모양이 사각형(RECTANGLE)일 때만 쓰인다.
    double length;
    double width;

    // 다음 필드는 모양이 원(CIRCLE)일 때만 쓰인다.
    double radius;

    // 원용 생성자
    public FigureWithTag(double radius) {
        this.shape = Shape.CIRCLE;
        this.radius = radius;
    }

    // 사각형용 생성자
    public FigureWithTag(double length, double width) {
        this.shape = Shape.RECTANGLE;
        this.length = length;
        this.width = width;
    }

    double area() {
        switch (shape) {
            case RECTANGLE:
                return length * width;
            case CIRCLE:
                return Math.PI * (radius * radius);
            default:
                throw new AssertionError(shape);
        }
    }
}

두 가지 이상의 의미를 표현할 수 있으며, 그중 현재 표현하는 의미를 태그값으로 알려주는 클래스다. (사실 본적이 없다). 위의 코드는 원과 사각형을 표현할 수 있다.

단점

  • 열거 타입, 태그 필드, switch문 등 쓸데 없는 코드가 많다.
  • 여러 구현이 섞여 있어 가독성이 나쁘다
  • 다른 의미를 위한 코드도 함께하니 메모리 비효율적이다.
  • 인스턴스 타입만으로 현재 의미를 알 길이 없다.

대체

추상 클래스를 정의하고, 태그 값에 따라 동작이 달라지는 메서드들을 루트 클래스의 추상 메서드로 선언하면 된다. 태그에 상관없이 동작이 일정한 메서드는 루트 클래스에 일반 메서드로 구현하면된다. 공통으로 사용하는 데이터 필드도 루트 클래스로 올린다.

public abstract class Figure {
    abstract double area();
}

public class Circle extends Figure {
    final double radius;

    public Circle(double radius) {
        this.radius = radius;
    }

    @Override
    double area() {
        return Math.PI * (radius * radius);
    }
}

public class Rectangle extends Figure {
    final double length;
    final double width;

    public Rectangle(double length, double width) {
        this.length = length;
        this.width = width;
    }

    @Override
    double area() {
        return length * width;
    }
}

0개의 댓글