본문 바로가기
Java/Effective Java

[이펙티브 자바 item23] 태그 달린 클래스보다는 클래스 계층구조를 사용해라

by bloodFinger 2021. 2. 17.

 

태그 클래스

public class Figure {
	enum Shape {RECTANGLE , CIRCLE};
	
	//태그 필드 - 현재 모양을 나타냄
	final Shape shape;
	
	//다음은 RECTANGLE 일경우 사용
	double length;
	double width;
	
	//다음은 CIRCLE 일경우 사용
	double radius;
	
	//RECTANGLE 생성자
	Figure(double redius){
		shape = Shape.RECTANGLE;
		this.radius = redius;
	}
	
	//CIRCLE 생성자
	Figure(double length , double width){
		shape = Shape.CIRCLE;
		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);
		}
		
	}

}

 

위의 클래스를 보면 하나의 클래스에서 여러가지 경우를 분류해서 사용하려고 한다.

어떻게 보면 하나의 클래스에서 잘 분류해서 사용한다고 생각 할 수 있지만 유지보수적인 측면에서 보면 정말 별로이다.

또한, 분류하기 위해서는 꼭 사용해야 하는 메소드가 존재하기 때문에 실수가 생길수 있다.

그러한 부분을 보완하기 위해서는 아래와 같이 계층 구조로 클래스를 작성하면 좋다.

 

 

 

클래스 계층 구조

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 Retangle extends Figure{
	final double length;
	final double width;
	
	Retangle(double length , double width) {
		this.length = length;
		this.width = width;
	}
	
	@Override
	double area() {
		return length * width;
	}
	
}

 

 

 

장점 : 

 

간결하고 , 명확해졌으며 쓸데 없는 코드도 모두 사라져 버렸다.

각 클래스의 생성자가 모든 필드를 남김없이 초기화하고 추상 메서드를 모두 구현했는지 컴파일러가 확인해준다.

실수로 빼먹은 case 문 때문에 런타임 오류가 발생할 일도 없다.

루트 클래스의 코드를 건드리지 않고도 다른 프로그래머가 독립적으로 계층구조를 확장하고 함께 사용 가능하다.

 

 

예를 들어) 마름모를 추가한다고 가정해보자

 

태그 클래스에서는 많은 부분을 수정하고 만들어야한다.

하지만 계층구조 클래스에서는

 

class Sqare extends Rectangle {
    Square(double side){
    	super(side,side);
    }
}