책에서 말하는 단점이 많은 형태의 클래스를 먼저 보고 시작하자.

class Figure {
    enum Shape { RECTANGLE, CIRCLE };

    //태그 필드 - 현재모양을 나타낸다.
    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) {
        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문 등 쓸데없는 코드가 너무 많다.

가독성도 좋지 않다.

 

한 클래스에 짬뽕처럼 중구난방으로 섞여있기 때문에 장황하고 오류를내기 쉽고 비효율적인 코드다.

 

자바를 어느정도 공부해봤다면 위의 클래스가 깔끔하지 않다는 것 까진 쉽게 알 수 있지만

어떻게 개선해야 하는가? 라고 한다면 고민이 될 수도 있다.

 

저자는 이런 태그달린 클래스를 계층구조로 바꾸라고 한다.

방법은 다음과 같다.

 

계층구조의 루트가 될 추상 클래스를 정의하고 태그 값에 따라 동작이 달라지는 메소드들을

루트 클래스의 추상 메소드로 선언한다.

 

거기에 루트 클래스를 확장한 구체 클래스를 의미별로 하나씩 정의한다.

변환한 코드를 보면서 이해해보자.

abstract class Figure {
    abstract double area();
}

class Circle extends Figure {
    final double radius;

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

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

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; }
}

Figure 추상 클래스를 만들어 상속받은 형태이다.

이렇게 하면 쓸데 없는 코드도 사라지고 클래스별로 의미가 남기 때문에 가독성도 좋아진다.

 

이런 예시에서 볼 수 있듯이 태그 달린 클래스를 써야 하는 상황은 거의 없다.

 

새로운 클래스를 작성하는 데 태그 필드가 등장한다면 태그를 없애고 계층구조로 대체하는 방법을

고민해보는 것이 좋다.

+ Recent posts