Study/object

[엘레강트 오브젝트] 3-7장 인트로스펙션과 캐스팅을 피하세요

에디개발자 2021. 9. 27. 07:00
반응형

나를 닮았다고 한다...

이 글은 엘레강트 오브젝트 새로운 관점에서 바라본 객체지향 도서를 보며 스터디한 글입니다.

책에서 주장하는 내용을 정리하였으며 예제들은 모두 코틀린 코드로 변환하여 작성하였습니다.

 

목차

  1. 인트로스펙션을 피하세요
  2. 캐스팅을 피하세요
  3. 정리

1. 인트로스펙션을 피하세요

타입 인트로스펙션은 리플렉션이라는 더 포괄적인 용어로 불리는 여러 가지 기법들 중 하나입니다. 리플렉션을 사용하면 메서드, 명령어, 구문, 클래스, 객체, 타입을 변경할 수 있습니다. 리플렉션은 매우 강력한 기법이지만 유지보수를 어렵게 만드는 안좋은 기법입니다.

fun <T> size(items: Iterable<T>): Int {
    if (items is Collection) {
        return items.size
    }
    var size = 0
    for (item in items) {
        ++size
    }
    return size
}

위 코드는 인자값의 타입을 확인한 뒤 처리하고 있습니다. 매우 훌륭한 코드처럼 보이지만 잘못된 방법입니다. 타입에 따라 객체를 차별하기 때문에 OOP의 기본 사상에 맞지 않습니다. items라는 객체의 타입에 따라 완전히 다른 방식으로 처리하기 때문에 객체가 스스로 결정을 내릴 수 없고 배제를 시키기 때문입니다. 또한 런타임에 객체의 타입을 조사하는 것은 클래스 사이의 결합도가 높아지기 때문에 좋지 않습니다.

 

메서드 오버로딩 기법을 이용하여  위 코드를 개선해보겠습니다.

fun <T> size(items: Iterable<T>): Int {
    var size = 0
    for (item in items) {
        ++size
    }
    return size
}

fun <T> size(items: Collection<T>): Int = items.size

 

2. 캐스팅을 피하세요

클래스 캐스팅 또한 이전에 작성한 내용과 동일합니다. 코드로 살펴보겠습니다.

코틀린 기능 스마트 캐스팅!!
앞서 타입 체크한 경우 후에는 자동으로 캐스팅되어 사용할 수 있습니다.
if (items is Collection) {
    return items.size   
}

이 코드는 items 의 타입을 확인하고 내부 메서드를 실행하고 있습니다. 대강보면 훌륭한 코드로 오해할 수 있지만 좋지 않은 방법입니다. 이유는 Collection이라는 클래스와 결합도가 숨겨져 있기 때문입니다. 다음에 다른 타입을 검사할 때 else if가 추가되고 또 다른 타입이 추가되면 또 else if... 코드가 매우 난잡해질 것 입니다.

 

정리

Java에서 instanceof 연산자( Kotlin에서 is 연산자 )를 사용하거나 클래스를 캐스팅하는 일은 안티패턴입니다. 리플렉션과 함께 이런 기능들을 제공하지만 사용은 피하도록 합니다.

반응형