[Effective Java] 아이템 23 : 태그 달린 클래스보다는 클래스 계층구조를 활용하라

HyeBin, Park·2022년 6월 29일
0

Effective Java Study

목록 보기
18/20
post-thumbnail

아이템 23 - 태그 달린 클래스보다는 클래스 계층구조를 활용하라

태그 달린 클래스?

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.length;
        this.length = length;
        this.width = width;
    }
    
    double area() {
    	swtich(shape) {
        	case RECTANGLE:
				return length * width;
            case CIRCLE:
            	return Math.PI * (radius * radius);
            default:
            	throw new AssertionError(shape);
        }
    }
}
  • 태그
    • 클래스의 타입에 대한 정보를 가지고 있는 멤버 필드를 의미한다.

태그 달린 클래스의 단점

  • 열거 타입 선언, 태그 필드, switch문 등 쓸데없느 코드가 많다.

  • 여러 구현이 한 클래스에 혼합돼 있어서 가독성이 나쁘다.

  • 다른 의미를 위한 코드도 언제나 함께 하니 메모리도 많이 사용한다.
    => length, width, radius ...

  • 필드들을 final로 선언하려면 해당 의미에 쓰이지 않는 필드들까지 생성자에서 초기화 해야한다.
    => 컴파일러가 잡아줄 수 없고 런타임에야 문제가 드러난다.

  • 다른 의미(타입)를 추가하려면 코드를 수정해야한다.
    => switch문 ..

  • 인스턴스의 타입만으로는 현재 나타내는 의미(타입) 를 알 길이 전혀 없다.

  • 태그 달린 클래스는 장황하고, 오류를 내기 쉽고, 비효율적이다.

대안 1) 서브 타이핑 (클래스 계층 구조)

abstract class Figure {
	abstract double area();
}

class Circle extends Figure {
	final double radius;
	
    Circle(double radius) {this.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;}
}
  • 계층구조의 루트가 될 추상 클래스를 정의한다.
  • 태그 값에 따라 동작이 달라지는 메서드들을 루트 클래스의 추상 메서드로 선언한다
    => Figure 클래스의 area 메서드
  • 태그 값에 상관없이 동작이 일정한 메서드들을 루트 클래스에 일반 메서드로 추가
  • 모든 하위 클래스에서 공통으로 사용하는 데이터필드들도 전부 루트 클래스로 올린다.
  • 루트 클래스를 확장한 구체 클래스를 의미별로 하나씩 정의한다.

서브 타이핑 장점

  • 관련 없던 데이터 필드를 모두 제거 하고, 살아 남은 필드들은 모두 final 이다.
  • 각 클래스의 생성자가 모든 필드를 남김없이 초기화하고 추상 메서드를 모두 구현했는지 컴파일러가 확인해준다.
  • 루트 클래스의 코드를 건드리지 않고도 다른 프로그래머들이 독립적으로 계층구조를 확장하고 함께 사용할 수 있다.
  • 타입별로 존재하니 변수의 의미를 명시하거나 제한할 수 있고, 또 특정 의미만 매개변수로 받을 수 있다.
  • 타입 사이의 자연스로운 계층 관계를 반영할 수 있어서 유연성은 물론이고 컴파일 타임 타입 검사 능력을 높여준다는 장점도 있다.

Figure 클래스에 정사각형을 만드려면?

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

0개의 댓글