diff --git "a/1\354\236\245/1_\354\203\235\354\204\261\354\236\220_\353\214\200\354\213\240_\354\240\225\354\240\201 \355\214\251\355\204\260\353\246\254_\353\251\224\354\204\234\353\223\234\353\245\274_\352\263\240\353\240\244\355\225\230\353\235\274_\354\265\234\353\235\275\354\244\200.md" "b/1\354\236\245/1_\354\203\235\354\204\261\354\236\220_\353\214\200\354\213\240_\354\240\225\354\240\201 \355\214\251\355\204\260\353\246\254_\353\251\224\354\204\234\353\223\234\353\245\274_\352\263\240\353\240\244\355\225\230\353\235\274_\354\265\234\353\235\275\354\244\200.md" new file mode 100644 index 0000000..663e246 --- /dev/null +++ "b/1\354\236\245/1_\354\203\235\354\204\261\354\236\220_\353\214\200\354\213\240_\354\240\225\354\240\201 \355\214\251\355\204\260\353\246\254_\353\251\224\354\204\234\353\223\234\353\245\274_\352\263\240\353\240\244\355\225\230\353\235\274_\354\265\234\353\235\275\354\244\200.md" @@ -0,0 +1,124 @@ +# 생성자 대신 정적 팩토리 메소드를 고려하라. + +## 1. 개요 + +클라이언트가 클래스의 인스턴스를 얻는 수단은 다음과 같이 두 가지로 나눌 수 있다. +* public 생성자 +```java +public Book(){} +``` +* 정적 팩터리 메서드 +```java +public static Book createBook(){ + return instance(); +} +``` +일반적인 public생성자에 비해 정적 팩터리 메서드는 다양한 장점을 가지고 있다. +그 장점이 무엇인지 알아보자. + +## 2. 정적 팩터리 메서드의 장점 +--- +### (1). 이름을 가질 수 있다. +* 정적 팩터리 메소드는 '메소드'이기 때문에 이름을 가질 수 있다. +* 그 이름을 통해 해당 정적 메서드가 어떤 특징을 갖는지, `어떤 인스턴스를 반환하는지 명시적으로 표현`할 수 있다. + +--- + +### (2). 호출될 때마다 인스턴스를 새로 생성하지는 않아도 된다. +정적 팩터리 메서드를 통해 `인스턴스 캐싱`과 `인스턴스 통제`를 활용할 수 있다. + +1). `인스턴스 캐싱` +- 인스턴스를 미리 생성해 놓고, 필요할 때마다 이를 가져다 쓰는 방식을 뜻한다. +- 불필요한 객체 생성을 피하고, 객체 생성의 비용을 줄여 준다. + +2). `인스턴스 통제` +- 해당 인스턴스의 생명주기를 통제하는 것을 뜻한다. +- 인스턴스를 통제하는 이유 + + 싱글턴을 만들기 위해 + + 인스턴스화 불가로 만들기 위해 + + 불변 클래스에서 값(value)이 같은 인스턴스는 단 하나임을 보장 + + +--- +### (3). 반환 타입의 하위 타입 객체를 반환할 수 있는 능력이 있다. +정적 팩터리 메서드의 리턴 타입을 인터페이스로 할 경우 하위 타입 객체를 반환 할 수 있다. +이는 주로 동반 클래스에서 볼 수 있다. + +>동반 클래스 : 자바 1.8 이전에는 인터페이스에 정적 메서드를 선언할 수 없었다. 따라서 인터페이스에 기능을 추가하기 위해서는 `동반 클래스`라는 것을 만들어 그 안에 정적 메서드를 추가했다. + +``` +인터페이스 Collection의 동반 클래스 -> Collections +``` +다음은 Collections 클래스의 정적 팩토리 메소드 unmodifiableList의 모습이다. +```java +public static List unmodifiableList(List list) { + return (list instanceof RandomAccess ? + new UnmodifiableRandomAccessList<>(list) : + new UnmodifiableList<>(list)); +} +``` +* 이와 같이 팩터리 메서드를 통해 `메소드의 반환 타입은 List이지만 실제로는 List의 하위 객체를 반환`시킬 수 있다. +* 이럴 경우의 장점은, 사용자들이 해당 인터페이스의 구현체를 일일이 알아 볼 필요가 없다는 것이다. + +--- +### (4). 입력 매개변수에 따라 매번 다른 클래스의 객체를 반환할 수 있다. +다음은 EnumSet의 정적 팩터리 메서드이다. +메서드 내부에서 `universe.length 따라 리턴 타입을 다르게` 반환 한다. +```java +public static > EnumSet noneOf(Class elementType) { + Enum[] universe = getUniverse(elementType); + if (universe == null) + throw new ClassCastException(elementType + " not an enum"); + + if (universe.length <= 64) + return new RegularEnumSet<>(elementType, universe); + else + return new JumboEnumSet<>(elementType, universe); + } +``` +* 이와 같이 팩터리 메서드를 통해 `사용자가 내부의 구현에 대해 알 필요 없이` 원하는 반환 값을 전달 받을 수 있다. +* 또한 메서드의 내부 구현이 변경되어도, 반환타입만 같다면 사용자에게 영향을 끼치지 않는다. +--- + +## 3. 정적 팩터리 메서드의 단점 +--- + +### (1). 상속을 하려면 public이나 protected 생성자가 필요하니 정적 팩터리 메서드만 제공하면 하위 클래스를 만들 수 없다. +* 상속을 위해서는 하위 클래스에서 사용할 수 있는 생성자가 필요하다. +* private 생성자를 통해 외부 생성을 막고, 정적 팩터리 메서드만을 사용하여 인스턴스를 반환할 경우, 하위 클래스를 만들 수 없다. + +### (2) 정적 팩터리 메서드는 프로그래머가 찾기 어렵다. +* 생성자는 이름이 클래스의 이름과 같아서 명확히 알 수 있다. +* 하지만 정적 팩터리 메서드는 다른 메서드와 섞여 찾기 어려울 수 있다. + +## 4. 정적 팩터리 메서드의 네이밍 +정적 팩터리 메서드는 찾기 어렵다는 단점 때문에, 일반적으로 쓰이는 네이밍 방식들이 있다. +그 내용은 다음과 같다. + +* from : 매개변수를 하나 받아, 해당 타입의 인스턴스를 반환하는 형변환 메서드 +```java +// instant 타입을 Date로 변환하여 반환 +Date d = Date.from(instant); +``` +* of : 매개변수를 여러개 받아 적합한 타입의 인스턴스를 반환하는 집계 메서드 +```java +// 파라미터로 전달 받은 타입의 Enum을 담은 Set을 반환 +Set faceCards = Enumset.of(JACK, QUEEN, KING); +``` +* valueOf : from과 of의 더 자세한 버전 +* instance 혹은 getInstance : 인스턴스를 반환, 그러나 같은 인스턴스임을 보장하지는 않음. +* create 혹은 newInstance : 새로운 인스턴스 생성하여 반환 +* getXXX : getInstance와 같으나, 생성할 클래스가 아닌 다른 클래스에 팩터리 메서드를 정의할 때 사용. +```java +// Files 클래스에서 FileStore의 인스턴스를 반환 +FileStore fs = Files.getFileStore(path); +``` +* newXXX : newInstance와 같으나, 생성할 클래스가 아닌 다른 클래스에 팩터리 메서드를 정의할 때 사용. +```java +// Files 클래스에서 BufferedReader를 반환 +BufferedReader br = Files.newBufferedReader(path); +``` +* xxx : getXXX과 newXXX의 간결한 버전 +```java +List litany = Collections.list(legacyListany); +``` \ No newline at end of file