⇒ 1) public 생성자 2) 정적 팩터리 메서드**
클래스의 인스턴스를 얻는 정통적인 수단
public class Person {
public Person() {
}
}
클래스의 인스턴스를 반환하는 단순한 정적 메서드 (*디자인 패턴에서의 팩터리 메서드와는 다른 것)
예를 들면?
Arrays, Collections 클래스에서 사용하는 메서드들
int[] nums = { 1, 2, 3, 4, 5 };
Arrays.asList(nums);
Collections.sort(list);
선언 방법
public class Person {
private static Person PERSON = new Person();
private Person() { // 외부에서 생성하지 못하도록 함
}
public static final Person getInstance() { // factory method
return PERSON;
}
}
즉, static으로 선언된 메서드이며 new Object()와 같이 객체 생성을 하지 않고 사용할 수 있는 메서드
이름을 가질 수 있다.
“생성자”를 사용할 경우
public class Foo {
public Foo(String name) { ... }
public Foo(String name, String address) { ... }
}
public class Foo {
public Foo(String name) { ... }
public Foo(String address) { ... } // 컴파일 에러
}
“정적 팩터리 메서드”를 사용할 경우
public class Foo {
public Foo() { ... }
public static withName(String name) {
Foo foo = new Foo();
foo.name = name;
return foo;
}
public static withAddress(String address) {
Foo foo = new Foo();
foo.address = address;
return foo;
}
}
<aside> 👉
한 클래스에 시그니처가 같은 생성자가 여러 개 필요할 것 같으면, 생성자를 정적 팩터리 메서드로 바꾸고 각각의 차이를 잘 드러내는 이름을 지어주자.
</aside>
호출될 때마다 인스턴스를 새로 생성하지 않아도 된다.
정적 팩터리 방식의 클래스는 **’반복되는 요청에 같은 객체를 반환하는 식’**으로 언제 어느 인스턴스를 살아 있게 할지를 철저히 **‘통제’**할 수 있음
통제하는 이유?: 다양한 장점이 있기 때문!
불변 클래스도 인스턴스를 미리 만들어 놓거나 새로 생성한 인스턴스를 캐싱하여 재활용하는 식으로 불필요한 객체 생성을 피할 수 있음
**플라이웨이트 패턴(Flyweight pattern)’**도 이와 비슷한 기법
반환 타입의 하위 타입 객체를 반환할 수 있는 능력이 있다.
= 메서드 호출을 통해 얻을 객체의 인스턴스를 자유롭게 선택할수 있는 유연성을 갖는다는 것 !!
interface SmarPhone {}
class Galaxy implements SmarPhone {}
class IPhone implements SmarPhone {}
class Huawei implements SmarPhone {}
class SmartPhones {
public static SmarPhone getSamsungPhone() {
return new Galaxy();
}
public static SmarPhone getApplePhone() {
return new IPhone();
}
public static SmarPhone getChinesePhone() {
return new Huawei();
}
}
대표적인 예시?: 자바 컬렉션 프레임워크인 java.util.Collections 클래스!
Collections 클래스는 Collection 인터페이스의 이름에 's' 를 붙여서 사용함!
이것을 Collection 인터페이스의 동반 클래스(Companion Class) 라고 부름
자바 8부터는 이 제한이 풀려서 더이상 동반 클래스 개념이 필요없어짐
interface SmarPhone {
public static SmarPhone getSamsungPhone() {
return new Galaxy();
}
public static SmarPhone getApplePhone() {
return new IPhone();
}
public static SmarPhone getChinesePhone() {
return new Huawei();
}
}
입력 매개변수에 따라 매번 다른 클래스의 객체를 반환할 수 있다.
interface SmarPhone {
public static SmarPhone getPhone(int price) {
if(price > 100000) {
return new IPhone();
}
if(price > 50000) {
return new Galaxy();
}
return new Huawei();
}
}
<aside> 👉
즉, 클라이언트는 팩터리가 건네주는 객체가 어느 클래스의 인스턴스인지 알 수도 없고 알 필요도 없음! 반환 타입의 하위 타입이기만 하면 됨!!
</aside>
정적 팩터리 메서드를 작성하는 시점에는 반환할 객체의 클래스가 존재하지 않아도 된다.