객체를 생성하는 방법 (인스턴스화)
- public 생성자
- public static 팩토리 메소드
정적 팩터리 메서드가 생성자 보다 좋은 장점 5가지
생성자 : 생성자가 제공하는 파라미터와 그 반환 객체를 잘 설명하지 못할 수 있음
⇒ 정적 팩터리 메서드 : 잘 만든 이름을 가질 수 있도록 만들 수 있다.
public class Foo {
String name;
public Foo(String name) {
this.name = name;
}
public static Foo withName(String name) { // 이름을 가질 수 있다.
return new Foo(name);
}
public static void main(String[] args) {
Foo foo = new Foo("hyungwoo");
Foo foo1 = Foo.withName("hyungwoo");
}
}
2. 호출될 때마다 인스턴스를 새로 생성하지는 않아도 된다.
불변(immutable) 클래스 이거나, 매번 새로운 객체를 만들 필요가 없는 경우
⇒ 미리 만들어 둔 인스턴스 or 캐시해둔 인스턴스를 반환한다.
package item01;
public class Foo {
public Foo() {
}
private static final Foo GOOD_NIGHT = new Foo(); // 미리 만들어둔 인스턴스
public static Foo getFoo() {
return GOOD_NIGHT;
}
public static void main(String[] args) {
Foo foo2 = Foo.getFoo(); // 미리 만들어 둔 인스턴스 반환
}
}
3. 반환 타입의 하위 타입 객체를 반환할 수 있는 능력이 있다.
public interface FooInterface {
public static Foo getFoo() {
return new Foo();
}
}
이렇게 구현체를 인터페이스 안에서 반환 시키는 메서드를 만들 수 있음. (Foo가 FooInterface를 implements했다고 가정)
클래스에서 만들어줄 객체의 클래스를 선택
할 수 있는 유연함이 있다.
⇒ ex) 리턴 타입을 인터페이스
로 지정하고 그 인터페이스의 구현체
는 API로 노출 시키지 않으면서 그 구현체의 인스턴스를 리턴 타입으로 반환할 수 있다.
자바 8 이전 : 인터페이스에 public static 메소드 추가 제한
⇒ 인터페이스에 인스턴스화 불가한 동반 클래스를 만들어 그 안에 정적 메서드로 제공 (java.util.Collections
가 대표적인 예)
⇒ java.util.Collections
가 45개 클래스를 공개하지 않고 제공 ⇒ 클라이언트는 인터페이스만으로 코딩 가능.
자바 8 이후 : 인터페이스에 public static 메소드 추가 가능
⇒ 인터페이스와 함께 동반 클래스를 만들 필요 없이 인터페이스에 public static 메소드를 추가하면 됨.
⇒ 하지만 인터페이스의 public static 메소드를 구현하기 위한 코드중 default 클래스에 둬야 하는 경우가 있음. (이부분 다시 읽어보기)
참고 : private static이 필요한 이유 ⇒ private 메서드가 있어야 하는 이유와 동일 ⇒
scope의 문제
⇒ private이 말그대로 그 클래스 밖에서 쓰이기 싫듯이, private static은 static 메서드에서 외부에 공개 되지 않은 메서드(private static)을 사용하고 싶을때 필요함.
4. 입력 매개변수에 따라 매번 다른 클래스의 객체를 반환할 수 있다.
장점 3의 연장선상이다.
public class Foo {
String name;
public Foo() {
}
public static Foo getFoo(boolean flag) {
return flag ? new Foo() : new BarFoo(); // 매개 변수에 따라 다른 클래스 객체 반환
}
public static void main(String[] args) {
Foo foo = Foo.getFoo(false);
}
static class BarFoo extends Foo {
}
}
EnumSet 클래스의 경우, public static 메소드인 allOf(), of()를 제공함
⇒ 이 메소드의 리턴 타입은 enum 타입의 갯수에 따라 RegularEnumSet
or JumboEnumSet
으로 달라진다. (구현체 반환이 다름)
⇒ 이 구현체들은 숨겨둔 것들이기 때문에 클라이언트는 몰라도 됨.
public class Foo {
String name;
public Foo() {
}
public static void main(String[] args) {
EnumSet<Color> colors = EnumSet.allOf(Color.class);
EnumSet<Color> blueAndWhite = EnumSet.of(RED, WHITE);
// Enum 갯수에 따라 인스턴스가 달라진다.
// 싱글톤인지는 테스트 해봐야함
}
enum Color {
RED, BLUE, WHITE
}
}
5. 정적 팩터리 메서드를 작성하는 시점에는 반환할 객체의 클래스가 존재하지 않아도 된다.
쉽게 말해서 정적팩터리 메서드 리턴타입이 인터페이스(클래스가 존재하지 않음) 여도 된다는 거임. 결국 3, 4 장점의 연장선상 이다. 리턴타입은 인터페이스지만 실제로 리턴을 구현체로 리턴해도 되기 때문이다.
public interface FooInterface {
}
public class Foo implements FooInterface {
public static FooInterface getFoo() {
return new Foo();
}
}
'Book > 이펙티브 자바 3' 카테고리의 다른 글
아이템 2. 생성자에 매개변수가 많다면 빌더를 고려하라. (0) | 2022.03.25 |
---|