[핵심 정리]
- 태그 달린 클래스를 사용할거라면 클래스 계층 구조를 활용해서 이를 대체하자 이는 완벽하게 태그 달린 클래스의 단점을 상쇄시키기 충분하다.
- 태그 필드가 등장한다면 태그를 없애고 계층구조로 대체하자. 기존 코드가 태그 필드를 사용하고 있다면 이를 리팩토링하는 방안을 고려하자.
public class Figure {
enum Shape {RECTANGLE, CIRCLE}
//태그 필드 - 현재 모양을 나타낸다.
private Shape shape;
// 다음 필드들은 모양이 사각형일 때만 사용.
private double length;
private double width;
// 다음 필드들은 모양이 원일 때만 싸용.
private double radius;
//원용 생성자
public Figure(double radius) {
shape = Shape.CIRCLE;
this.radius = radius;
}
//사각형용 생성자
public Figure(double length, double width) {
shape = Shape.RECTANGLE;
this.length = length;
this.width = width;
}
private double area() {
switch (shape) {
case RECTANGLE:
return length + width;
case CIRCLE:
return Math.PI * (radius * radius);
default:
throw new AssertionError(shape);
}
}
}
area()
가 해당 작업에 해당한다. area()
만 추상 클래스 안에 추상 메서드로 넣어두면 된다.
// root를 추상 클래스로 만든다
abstract class Figure {
// 태그 값에 따라서 동작이 달라지는 area() 메서드의 경우엔 추상 메서드로 선언해주자
abstract dobule 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;}
}