Categories
자바

객체 생성과 소멸

생성자 대신 static factory 메소드 사용을 고려하자

자바에서의 객체의 생성과 소멸에 대한 이야기입니다. 즉, 객체를 언제 어떻게 생성하고 소멸 전에 어떤 클린업 작업을 해야 하는지 다룹니다. 오늘 글은 이펙티브 자바 챕터 2장을 참고하여 작성된 글입니다. 일반적으로 클래스 인스턴스를 생성은 public constructor를 통해 생성합니다. 그러나 클래스에 public static 팩토리 메소드를 사용하여 그 클래스의 인스턴스를 하나만 생성하는 것이 효율적입니다. 다음의 Boolean boxed primitive 클래스 예를 보자. 이 클래스는 boolean 기본형 값을 인자로 받아 Boolean 객체 참조로 변환하여 반환합니다.

public static Boolean valueOf(boolean b) {
    return b ? Boolean.TRUE : Boolean.FALSE;
}

이 static 팩토리 메소드는 Design Patterns에 나오는 팩토리 메소드(Factory Method) 패턴과 다릅니다. 이 클래스에서는 생성자를 대신하여 static 팩토리 메소드를 가질 수 있습니다. public 생성자 대신 static 팩토리 메소드를 제공하면 다음과 같은 장단점이 있습니다. Static 팩토리 메소드의 한 가지 장점은, 생성자와 달리 자기 나름의 이름을 가질 수 있다는 것이다. 만일 생성자에 전달되는 매개변수가 반환 객체를 잘 나타내지 못한다면, 이름을 잘 지은 static 팩토리 메소드가 더 사용하기 쉬우며, 이 메소드를 호출하는 클라이언트 코드도 이해하기 쉽습니다. 예를 들어, Big Integer (int, int, Random) 생성자에서는 소수인 Big Integer 인스턴스를 생성하는데, 이 경우 BigInteger.probablePrime 이라는 이름의 static 팩토리 메소드를 사용하는 것이 더 이해하기 쉽습니다. 자바 클래스는 동일한 시그니처를 갖는 생성자를 하나만 가질 수 있습니다. 이런 제약을 해결하기 위해 프로그래머들은 타입이 다른 매개변수의 순서만을 바꾸어 두 개의 생성자로 만듭니다. 그러나 이 방법은 좋지 않습니다. 그 클래스의 사용자는 자신이 필요한 생성자가 어떤 것인지 기억하기도 어려울뿐더러, 실수로 다른 생성자를 호출 할 수도 있기 때문입니다. 또한 그런 생성자를 사용하는 코드를 파악하려는 사람들은 생성자가 정의된 클래스의 문서를 봐야만 그 코드를 이해할 수 있을 것입니다. static 팩토리 메소드는 자신의 이름을 가질 수 있으므로, 앞의 생성자와 같은 제약을 갖지 않습니다. 따라서 하나의 클래스에 동일한 시그니처를 갖는 여러 개의 생성자가 필요한 경우에는 생성자 대신 static 팩토리 메소드를 사용하되, 메소드 간의 차이점을 부각시키도록 신중하게 이름을 선정해야합니다. Static 팩토리 메소드의 두 번째 장점은, 생성자와 달리 호출될 때마다 매번 새로운 객체를 생성할 필요가 없다는 것입니다. 따라서 불변 클래스의 경우 이미 생성된 인스턴스를 다시 사용할 수 있으며, 불필요하게 중복된 인스턴스들이 생성되는 것을 방지하기 위해 이미 생성된 인스턴스들 을 저장했다가 반복 사용할 수 있습니다. 예를 들어, Boolean . valueOf 메소드에서는 인스턴스를 절대 생성하지 않습니다. 이 기법은 Flyweight 패턴과 유사하며, 동일한 객체(인스턴스)가 자주 사용될 때, 특히 객체 생성시 자원이나 시간이 많이 든다면 프로그램 성능을 크게 향상시킬 수 있습니다. static 팩토리 메소드는 여러 번 호출되더라도 이미 생성된 동일 객체를 반환할 수 있으므로, 클래스에서는 언제든지 인스턴스들의 존재를 직접 제어 할 수 있습니다. 이런 일을 하는 클래스를 인스턴스 제어(instance-controlled) 클래스라고 합니다. 인스턴스 제어 클래스를 만드는 이유는 몇 가지가 있습니다. 인스턴스를 제어하면 싱글톤(singleton) 또는 인스턴스 생성 불가(noninstantiable) 클래스로 만들 수 있습니다. 또한 불변 클래스에서 두 개의 동일한 인스턴스가 생기지 않도록 해줍니다. 그리고 클래스에서 이것을 보장해 준다면 인스턴스의 동일 여부를 확인할 때 equals (Object) 메소드 대신 == 연산자를 사용할 수 있으므로 프로그램 성능도 향상될 수 있습니다. 열거형(enum)에서는 이것을 보장하고 있습니다. 자신의 클래스 인스턴스만 반환하는 생성자와 달리, static 팩토리 메소드는 자신이 반환하는 타입의 어떤 서브타입(subtype) 객체도 반환할 수 있다는 것이 세 번째 장점이다. 이렇게 생성자 대신 static factory 메소드를 사용하는 장점을 알아봤습니다.