조슈아 블로크 님의 "Effective Java" 책을 정리한 포스팅 입니다.
1. 정적 팩토리 메서드
- 클래스는 생성자와는 별도로 static factory method 제공이 가능함
2. 장점
이름을 가짐
반환될 객체의 특성이 묘사되도록 할 수 있음
public static Order primeOrder(Product product) {
Order order = new Order();
order.prime = true;
order.product = product;
return order;
}
public static Order urgentOrder(Product product) {
Order order = new Order();
order.urgent = true;
order.product = product;
return order;
}
한 클래스에 시그니처가 같은 생성자가 여러 개 필요할 경우 유용
public class Order {
private Product product;
private boolean prime, urgent;
public Order(Product product, boolean urgent) {
this.product = product;
this.urgent = urgent;
}
public Order(Product product, boolean prime) {
this.product = product;
this.prime = prime;
}
}
- 동일 시그니처는 컴파일 에러가 발생함
호출될 때마다 인스턴스를 새로 생성하지 않아도 됨
캐시해둔 인스턴스를 재활용할 수 있음
public class Settings {
private boolean useAutoSteering;
private boolean useABS;
private Difficulty difficulty;
private Settings() {}
private static Settings SETTINGS = new Settings();
public static Settings newInstance() return SETTINGS;
}
- 플라이웨이트 패턴과 매우 유사함
- 불변 클래스를 다룰 때 유용
- 매개 변수에 따라 다른 인스턴스 객체를 리턴할 수 있음 (ex. Boolean.valueOf(boolean))
인스턴스 생성을 철저히 통제할 수 있음
- 싱글턴 클래스화
- 인스턴스화 불가
- 불변 클래스에서 동치인 인스턴스가 단 하나뿐임을 보장 (열거 타입)
반환 타입의 하위 타입 객체로 반환 가능
원하는 하위 타입 선택 가능
- 인터페이스
- 정적 메서드 사용 가능
- 기본 메서드 사용 가능
입력 매개변수에 따라 매번 다른 클래스의 객체 반환 가능
- 클라이언트는 어떤 서브클래스 객체를 반환받을지 생각할 필요 없음
정적 팩터리 메서드를 작성하는 시점에 반환할 객체의 클래스가 존재하지 않아도 됨
추상화 제공
public static void main(String[] args) {
String driverName = "com.mysql.jdbc.Driver";
String url = "jdbc:mysql://localhost:3306/test";
String user = "root";
String password = "soyeon";
try {
Class.forName(driverName);
// 서비스 접근 API인 DriverManager.getConnection가 서비스 구현체(서비스 인터페이스)인 Connection 반환
Connection connection = DriverManager.getConnection(url, user, password);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
- 반환값이 인터페이스여도 됨
- 인풋에 따라 자식클래스의 인스턴스 반환
- 클라이언트 코드와의 종속성을 낮추고 결합도를 느슨하게 함
- 이러한 유연함은 서비스 제공자 프레임워크를 만드는 근간이 됨
인스턴스를 만드는 일을 서브클래스에게 맡김
abstract class Shape {
protected DrawingAPI drawingAPI;
protected Shape(DrawingAPI drawingAPI) { this.drawingAPI = drawingAPI; }
public abstract void draw();
}
class CircleShape extends Shape {
private double x, y, radius;
public CircleShape(double x, double y, double radius, DrawingAPI drawingAPI) {
super(drawingAPI);
this.x = x;
this.y = y;
this.radius = radius;
}
public void draw() { drawingAPI.drawCircle(x, y, radius); }
}
- 추상화된 부분과 구현 부분을 서로 다른 클래스 계층구조로 분리
- 서로 영향을 주지 않으면서 독립적으로 확장하도록 하기 위함
- 브릿지 패턴과 유사
3. 단점
정적 팩토리 메서드만으로는 하위 클래스 생성 불가
- 상속을 하려면 public이나 protected 생성자 필요
프로그래머가 찾기 어려움
이름에 대한 규약을 따라 짓는 식으로 완화
Date d = Date.from(instant);
Set<Rank> faceCards = EnumSet.of(JACK, QUEEN, KING);
BigInteger prime = BigInteger.valueOf(Integer.MAX_VALUE);
StackWalker luke = StackWalker.getInstance(options);
Object new Array = Array.newInstance(classObject, arrayLen);
FileStore fs = Files.getFileStore(path);
BufferedReader br = Files.newBufferedReader(path);
List<Complaint> litany = Collections.list(legacyLitany);
- from
- 하나의 매개변수 받아, 해당 타입의 인스턴스 반환
- of
- 여러개의 매개면수를 받아, 적합한 타입의 인스턴스 반환
- valueOf
- from과 of의 더 자세한 버전
- getInstance
- 매개변수로 명시한 인스턴스 반환.
- 동일 인스턴스가 아님을 보장
- newInstance
- 매번 새로운 인스턴스 반환을 보장
- get"Type"
- getInstance와 같음
- 팩토리 클래스에서 해당 타입의 인스턴스를 반환할 때 사용
- new"Type"
- newInstance와 같음
- 팩토리 클래스에서 해당 타입의 인스턴스를 반환할 때 사용
'Java' 카테고리의 다른 글
[Effective Java] 2-3. 객체 생성과 파괴: private 생성자나 열거 타입으로 싱글턴임을 보장하라 (0) | 2024.12.27 |
---|---|
[Effective Java] 2-2. 객체 생성과 파괴: 생성자에 매개변수가 많다면 빌더를 고려하라 (0) | 2024.12.26 |
[JVM 밑바닥까지 파헤치기] 12-3. 자바 메모리 모델과 스레드: 스레드 (1) | 2024.12.26 |
[JVM 밑바닥까지 파헤치기] 12-2. 자바 메모리 모델과 스레드: 자바 메모리 모델 (1) | 2024.12.26 |
[JVM 밑바닥까지 파헤치기] 12-1. 자바 메모리 모델과 스레드: 동시성 (1) | 2024.12.25 |