Item23. 태그 달린 class보다는 class 계층 구조를 활용하자
2021-12-25 20:12:58
태그 달린 class
헌재 표현하는 의미를 태그 값으로 알려주는 class 는 아래와 같이 class 계층구조를 사용하지 않고, 한 class내에 태그 필드를 가지는 class를 말한다.
public class Figure {
enum Shape {RECTANGLE,CIRCLE};
// 현재 모양
final Shape shape;
// RECTANGLE일떄만 쓰이는 필드
double length;
double width;
// CIRCLE일떄만 쓰이는 필드
double radius;
// CIRCLE용 생성자
public Figure(double radius) {
this.shape = Shape.CIRCLE;
this.radius = radius;
}
// RECTANGLE용 생성자
public Figure(double length, double width) {
this.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);
}
}
}
-
태그 필드를 가지고, 분기처리 (swith,if-else)를 하기 때문에 코드 가독성이 떨어지고, 계층형 구조로 가져갔을때 불필요한 코드들이 생긴다.
-
태그 값마다 필요한 필드가 다른데, 이를 모두 하나의 class에 보관함으로, 객체를 생성하였을떄 사용되지 않는 필드 (메모리 낭비) 도 같이 초기화 된다.
-
변경에 열려있다, 태그 값 추가시마다 분기로직을 수정해야 한다.
-
인스턴스 타입을 보고 현재 타입이 나타내는 의미를 알 수가 없다.
클래스 계층 구조로 변경
- 태그 달린 class는 위와 같은 단점들을 가지고 있기 떄문에, 클래스 계층 구조로 변경하는게 더 바람직하다.
- 변경 방법을 정리하면 다음과 같다.
-
계층 구조의 부모가 될 추상 class를 정의
-
태그 값에 따라 동작이 달라지는 method를 자식이 구현하도록 abstract method로 선언
태그 값에 따라 동작이 달라지지 않는 method는 default method로 선언
-
구현체는 태그값(의미)별로 하나씩 정의
예제 코드를 보면 Figure class를 다음과 같은 클래스 계층구조로 변경하였다.
public abstract class Figure {
// 구현체마다 동작이 다른 추상 method
abstract double area();
}
태그값 (의미) 별로 구현체로 분리하였으며, 구현체마다 다른 로직은 추상 method로 뽑았다.
public class Circle extends Figure {
final double radius;
public Circle(double radius) {
this.radius = radius;
}
@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 ;
}
}
계층구조로 변경하면서 생긴 장점은 다음과 같다.
- 불필요한 분기로직 제거
- 타입만 보아도 해당 class가 무슨 기능을 하는지 짐작 할 수 있다. (가독성)
- 불필요한 필드 제거 , 해당 클래스에서 필요한 필드만 가지고 있다.
- 확장성 증가
예를 들어 직사각형 class를 상속받는 정사각형 class는 다음과 같이 간단히 표현될 수 있다.
public class Square extends Rectangle{
public Square(double side) {
super(side, side);
}
}
정리
태그 달린 class는 계층구조로 리팩토링 하자, 구현체간에 공통된 로직은 default method로 , 구현체마다 다른 로직은 abstract method로 선언하면 변경이 가능하다.
댓글
이 게시글에 대한 의견을 공유해주세요!
