Skip to content
Go back

[Effective Java] Item 23 태그달린 클래스보다는 클래스 계층구조를 활용하라

Edit page

태그(플래그) 달린 클래스

// 원과 사각형을 하나의 클래스로 표현
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);
        }
    }
}

위와 같이 태그 역할을 하는 필드를 통해 분류를 하는 방법이 존재한다. 하지만 이것은 OOP를 지원하는 Java에서 별로 좋지 못한 방법이다.

태그 클래스 단점

복잡해진다

보일러 플레이가 필요해진다. switch를 만들어거 각 태그에 맞는 구현도 필요해진다.

class Figure {
    enum Shape { RECTANGLE, CIRCLE }  // 1. enum 선언
    final Shape shape;                 // 2. 태그 필드
    
    // 3. switch 문이 모든 메서드에 반복
    double area() {
        switch(shape) { /* ... */ }
    }
    
    double perimeter() {
        switch(shape) { /* ... */ }
    }
}

메모리 낭비

아래 원의 경우 length, width이 필요 없음에도 다른 태그를 지원하기 위해서 변수가 필요하다.

Figure circle = new Figure(5.0);  // 원 생성

final 선언 불가

아래 필드들은 final로 사용할 수 없다. 생성자가 전부 초기화 하지 않기 때문이다.

class Figure {
    final Shape shape;
    
    // final로 만들 수 없음
    // 생성자에서 사용하지 않는 필드도 초기화해야 하기 때문
    double length;  
    double width;
    double radius;
}

계층구조로 리팩토링

1. 추상 클래스 생성

// 루트 클래스
abstract class Figure {
    abstract double area();
}

2. 구체 클래스 생성

// 원 클래스
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;
    }
}

정리

위와 같이 태그를 사용하는 대신 계층구조로 설계하여 이전보다 좋은 설계가 될 수 있다.


Edit page
Share this post on:

Previous Post
[Effective Java] Item 24 멤버 클래스는 되도록 static으로 만들라
Next Post
[OSTEP] 스케줄링: MLFQ(멀티 레벨 피드백 큐)