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

제롬·2022년 3월 15일
0

이펙티브자바

목록 보기
23/25

태그 달린 클래스의 정의

태그 달린 클래스란 두가지 이상의 의미를 표현할 때 그 중 현재 표현하는 의미를 태그값으로 알려주는 클래스를 말한다.

태그 달린 클래스의 단점

태그 달린 클래스에는 여러 단점이 있다.

  • 열거 타입 선언, 태그 필드, switch문 등 쓸데없는 코드가 많다.
  • 여러 구현이 한 클래스에 혼합돼 있어서 가독성이 나쁘다.
  • 다른 의미를 위한 코드도 사용하므로 메모리도 많이 사용한다.
  • 쓰이지 않는 필드를 초기화해야해서 불필요한 코드가 늘어난다.
  • 인스턴스 타입만으로는 현재 나타내는 의미를 알 수 없다.

[태그달린 클래스 - 계층구조보다 훨씬 나쁘다]

public class Figure {
    enum Shape {RECTANGLE, CIRCLE}

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

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

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


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

    public Figure(final double length, final 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);
        }
    }
}

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

만약, 다양한 의미의 객체를 표현해야 한다면 서브 타이핑(Subtyping)을 이용하는것이 더 좋은 방법이다.

서브타이핑(Subtyping)

타입 하나로 다양한 의미의 객체를 표현하는 수단으로 클래스 계층구조를 활용한다.

태그 달린 클래스를 계층구조로 바꾸는 방법

  1. 루트 클래스 작성
    • 루트가 될 추상 클래스를 정의한다.
    • 태그값에 따라 동작이 달라지는 메서드들을 루트 클래스의 추상 메서드로 선언한다.
    • 태그 값에 상관없이 동작이 일정한 메서드들을 루트 클래스에 일반 메서드로 추가한다.
    • 모든 하위 클래스에서 사용하는 공통 데이터 필드도 전부 루트 클래스에 작성한다.
  2. 루트 클래스를 확장한 구체 클래스를 의미별로 작성
    • 각각의 의미에 해당하는 데이터 필드를 넣는다.
    • 루트 클래스가 정의한 추상 메서드를 의미에 맞게 구현한다.

[태그 달린 클래스를 클래스 계층구조로 변환]

abstract class HierarchyFigure {
    abstract double area();
}

class Circle extends HierarchyFigure{
    final double radius;

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

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

class RECTANGLE extends HierarchyFigure{
    final double width;
    final double height;

    public RECTANGLE(final double width, final double height) {
        this.width = width;
        this.height = height;
    }

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

정리

새로운 클래스를 작성하는데 태그 필드가 등장한다면 태그를 없애고 계층구조로 대체하자. 또한 기존 클래스가 태그 필드를 사용하고 있다면 계층구조로 리팩토링하자.

0개의 댓글