1. 태그 달린 클래스
- 쓸데없는 코드가 너무 많다 : 열거 타입선언, 태그 필드, switch문
- 장황하고 오류를 내기 쉽고 비효율적이다.
- 클래스 계층 구조를 어설프레 흉내낸 것이다.
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);
}
}
}
2. 클래스 계층 구조로의 리팩터링
a. root가 될 추상 클래스를 정의하자
b. 태그에 따라 행동이 달라지던 메서드는 추상 메서드로 구현하자 : 그렇지않으면 일반메서드
c. 공통된 필드는 모두 root 클래스로 올리자
d. 구체 클래스에서 추상클래스를 의미에 맞게 정의하자
abstract class Figure {
abstract double area();
}
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; }
}
class Circle extends Figure {
final double radius;
Circle(double radius) { this.radius = radius; }
@Override double area() { return Math.PI * (radius * radius); }
}
class Square extends Rectangle {
Square(double side) {
super(side, side);
}
}