ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 아이템 23. 태그 달린 클래스보다는 클래스 계층구조를 활용하라
    Study/Effective Java 2023. 8. 10. 11:55

    두 가지 이상의 의미를 표현할 수 있으며, 그 중 현재 표현하는 의미를 태그 값으로 알려주는 클래스에 대한 예제이다.

    // 코드 23-1 태그 달린 클래스 - 클래스 계층구조보다 훨씬 나쁘다! (142-143쪽)
    class Figure {
        enum Shape {RECTANGLE, CIRCLE, SQUARE};
    
        // 태그 필드 - 현재 모양을 나타낸다.
        final Shape shape;
    
        // 다음 필드들은 모양이 사각형(RECTANGLE)일 때만 쓰인다.
        double length;
        double width;
    
        // 다음 필드는 모양이 원(CIRCLE)일 때만 쓰인다.
        double radius;
    
        // 원용 생성자
        Figure(double radius) {
            shape = Shape.CIRCLE;
            this.radius = radius;
        }
    
        // 사각형용 생성자
        Figure(double length, double width) {
            if (this.length == this.width) {
                shape = Shape.SQUARE;
            } else {
                shape = Shape.RECTANGLE;
            }
    
            this.length = length;
            this.width = width;
        }
    
        double area() {
            switch (shape) {
                case RECTANGLE, SQUARE:
                    return length * width;
                case CIRCLE:
                    return Math.PI * (radius * radius);
                default:
                    throw new AssertionError(shape);
            }
        }
    }

    태그 달린 클래스에는 단점이 한가득이다.

    1. 열거 타입 선언, 태그 필드, switch 문 등 쓸데없는 코드가 많다.
    2. 여러 구현이 한 클래스에 혼합되어 있어 가독성도 나쁘다.
    3. 다른 의미를 위한 코드도 언제나 함께하니 메모리도 많이 사용한다.
    4. 필드들을 final로 선언하려면 해당 의미에 쓰이지 않는 필드들까지 생성자에서 초기화해야 한다.
    5. 생성자가 태그 필드를 설정하고 해당 의미에 쓰이는 데이터 필드들을 초기화하는 데 컴파일러가 도와줄 수 있는 건 별로 없다. 엉뚱한 필드를 초기화해도 런타임에야 문제가 드러난다.
    6. 새로운 의미를 추가할 때마다 모든 switch 문을 찾아 새 의미를 처리하는 코드를 추가해야 한다. (예제의 SQUARE)
    7. 인스턴스의 타입만으로는 현재 나타내는 의미를 알 길이 전혀 없다.

    즉 태그 달린 클래스는 장황하고, 오류를 내기 쉽고, 비효율적이다.

    태그 달린 클래스는 클래스 계층구조를 어설프게 흉내낸 아류일 뿐이다.

    // 코드 23-2 태그 달린 클래스를 클래스 계층구조로 변환 (144쪽)
    abstract class Figure {
        abstract double area(); // 모든 도형에는 너비가 있다.
    }
    // 코드 23-2 태그 달린 클래스를 클래스 계층구조로 변환 (144쪽)
    class Circle extends Figure {
        final double radius;
    
        Circle(double radius) { this.radius = radius; }
    
        @Override double area() { return Math.PI * (radius * radius); }
    }
    // 코드 23-2 태그 달린 클래스를 클래스 계층구조로 변환 (144쪽)
    class Rectangle extends Figure {
        final double length;
        final double width;
    
        Rectangle(double length, double width) {
            this.length = length;
            this.width  = width;
        }
    
        @Override double area() { return length * width; }
    }
    // 태그 달린 클래스를 클래스 계층구조로 변환 (145쪽)
    class Square extends Rectangle {
        Square(double side) {
            super(side, side);
        }
    }

    클래스 계층구조는 태그 달린 클래스의 단점을 모두 날려버린다.

     

    댓글

Designed by Tistory.