// 태그 달린 클래스

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);
			defalut:
				throw new AssertionError(shape);
		}
	}
}

태그 달린 클래스의 단점

  1. 여러 구현이 한 클래스에 혼합돼 있어서 가독성이 나쁘다.
  2. 필드들을 final로 선언하려면 해당 의미에 쓰이지 않는 필드들까지 생성자에서 초기화 해야한다.
// 태그 달린 클래스를 클래스 계층구조로 변환
abstract class Figure {
	abstract double area();
}

class Circle extends Figure {
	 final double radius;
	 Circle(double radius) {
		 this.radius = radius;
	 }
	 
	 @Override
	 double area() {
		 return Math.PI * (radius * radius);
	 }
}

class Rectangel extends Figure {
	 final double length;
	 final double width;
	 
	 Circle(double length, double width) {
		 this.length= length;
		 this.width= width;
	 }
	 
	 @Override
	 double area() {
		 return length * width;
	 }
}