이 글은 Effective Java 를 완독하고, Kotlin 을 상용으로 사용하는 개발자 입장에서
Effective Kotlin 글 중 새로운 내용, remind 할 필요 있는 부분, 핵심 내용 등만 추려 정리한 내용입니다.
#
Factory function 의 장점은 아래와 같다.
- Constructor 와 다르게 이름을 가질 수 있다.
- Constructor 와 다르게 subtype 을 return 할 수 있다.
- Constructor 와 다르게 매번 새로운 object 를 만들지 않아도 된다. 기존에 만든 것을 줄 수도 있고, null 을 return 할 수도 있다.
- 아직 존재하지 않는 object 를 제공할 수 있다. 이는 annotation processing 기반으로 객체가 생성되는 경우를 이야기한다.
- 해당 객체 바깥쪽에 정의하는 경우 same file, same module 등의 visibility control 도 가능하다.
- Factory function 은 inline 될 수 있고, 따라서 type parameter 가 reified 될 수 있다.
- 복잡하게 생성해야 하는 것들을 간단하게 생성하도록 할 수 있다.
- Constructor 는 superclass 의 constructor 를 즉각적으로 불러야 하지만, factory 를 사용하면 이를 미룰 수 있다.
#
Factory function 은 주로 secondary constructor 들과 비슷한 계위이고, primary constructor 의 계위는 아니다. 그리고 또 다른 비슷한 factory function 와 같은 계위라고 볼 수 있다.
#
Kotlin 에는 다음의 factory function 들이 있다.
- Companion object factory function
- Extension factory function
- Top-level factory function
- Fake constructors
- Methods on a factory class
Companion Object Factory Function
#
해당 class 에 속해 있어 결속력이 좋고, java 를 비롯한 다른 언어에도 친숙한 패턴이다.
Java convention 에 따라 from, of, valueOf, getInstance, createInstance, newInstance, getType, newType 등의 이름이 많이 사용된다.
#
Companion object 가 interface 를 구현하거나, class 를 확장할 수 있다는 점에서 강력함을 보여준다.
예를 들면 companion object : ActivityFactory() { ... } 와 같이 사용할 수 있다.
Extension factory functions
#
기 존재하는 파일을 수정하지 않으면서 혹은 수정하지 못하는 환경에서 사용되는 방법이다.
단, 기 존재하는 파일에 empty 이더라도 companion object 가 정의되어 있어야 한다.
fun Tool.Companion.createBigTool( /.../) : BigTool{ /*... */}
Top-level functions
#
List, Map 과 같이 작으면서 자주 사용되는 object 생성에 좋다.
public top-level function 은 단점들이 있기 때문에 남용을 피하는 것이 좋다.
어디서든 접근 가능해서 IDE 가 tip 으로 추천한다던지 하는 단점이다. top-level function 이 접근하는 class 의 함수 이름처럼 되어 있을 때 혼란을 가져올 수 있어 치명적일 수 있다. 그래서 사용한다면 이름이 잘 지어져야 한다.
Fake constructors
#
val reference: () -> A = ::A
이런 식의 construct 도 가능하다.
#
convention 으로 class 는 대문자로 시작하고, function 은 소문자로 시작한다.
이런 점을 활용하여 다음과 같이 fake constructor 를 만들 수 있다.
public inline fun List(
size:Int,
init: (index: Int) -> T
) : List = MutableList(size, init)
convention 때문에 constructor 처럼 보이지만 사실은 function 이다.
#
실제 constructor 대신 fake constructor 를 만드는 2가지 이유는..
- interface 를 위한 constructor 를 갖기 위해
- reified type argument 를 갖기 위해
#
companion object 와 invoke operator 를 사용한 fake constructor 도 있다.
class Tree{
companion object{
operator fun invoke(size:Int, generator: (Int)->T): Tree{
// ...
}
}
}
Tree(10){ "$it" }
이 방법은 다음과 같은 혼란을 가져온다.
val f: ()->Tree = ::Tree // constructor
val f: ()->Tree = ::Tree // fake constructor
val f: ()->Tree = Tree.Companion::invoke // detail 하게 기술한 fake constructor
그래서 정말 특별한 이유가 있는 것이 아니면 top-level constructor 형태가 추천된다.
Methods on factory class
#
factory 관련된 창의적 패턴이 많이 있다. 예를 들면 abstract factory 나 prototype 이 그것이다.
#
Factory class 는 factory function 대비 상태를 가질 수 있다는 장점을 가지고 있다.
상태를 이용하여 cache, 기존 객체 copy 를 통한 create 등으로 최적화도 할 수 있다.
Summary
#
Factory function 은 fake constructor, top level factory method, extension factory function 등이 있는데, 가장 추천되는 것은 Companion Object 에 정의한 factory function 이다.
끝
댓글