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

태그 달린 클래스

두 가지 이상의 의미를 표현할 수 있으며, 그 중 현재 표현하는 의미를 태그 값으로 알려주는 클래스를 본 적이 있을 것이다. 다음이 그러하다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Figure {
enum Shape { RECTANGLE, CIRCLE };

final Shape shape;

double length;
double width;

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

태그 달린 클래스는 단점이 한가득이다. 열거 타입, 태그 필드, switch문 등 쓸데 없는 코드가 너무 많다. 태그 달린 클래스는 장황하고 오류를 내기 쉽고 비효율적이다. 계층구조를 어설프게 흉내낸 아류일 뿐이다.

계층구조

이를 계층구조로 뽑아내면 훨씬 깔끔한 코드가 된다. 상위 추상클래스에 태그 값에 따라 동작이 달라지는 메소드들을 추상 메소드로 선언하고 태그 값에 상관 없이 일정한 메소드들을 일반 메소드로 선언한다. 그 다음으로 이 추상 클래스를 확장한 구체 클래스를 정의하면 깔끔한 계층 구조가 나온다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public abstract class Figure {
abstract double area();
}

public class Circle extends Figure{
final double radius;

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

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

이렇게 계층구조로 표현하면 컴파일러가 필요한 메소드들을 구현했는지 확인해준다. 또한 다른 프로그래머들이 독립적으로 계층구조를 확장하고 함께 사용할 수 있다. 확장도 매우 쉽다.

1
2
3
4
5
public class Square extends Rectangle{
public Square(double side) {
super(side, side);
}
}
Author: Song Hayoung
Link: https://songhayoung.github.io/2020/08/09/Languages/Effective%20JAVA/item23/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.