[2019.03.09] 이팩티브 자바 3판 (1,2장 : 객체 생성 파괴)
2019. 3. 6. 00:33ㆍ[공부] 독서/이펙티브 자바 3판
1장
코드는 복사되는게 아니라 재사용 되야한다.
책의 목표 : 명료성, 단순성
객체를 생성하는법
- 생성자
- 정적 팩토리 메소드
정적 팩토리 메소드의 의미 : (메소드) 인데 클래스 밖에서 new 없이 메소드를 호출하기 위해선 static(정적)이여야 한다. 그리고 객체를 만들어주는 메소드이니까 (팩토리) 이다.
GoF 패턴에는 존재하지 않는 기법이다. 팩토리 메소드 패턴과는 다르다. 가능하면 생성자보다 이 방법을 사용하라.
참고
템플릿 메소드 패턴 : 메소드들이 템플릿화 되어 실행순서가 알고리즘 화 되도록 하는 것 onPrepare() -> onRun()-> onPost()
팩토리 메소드 패턴 : 팩토리 메소드 패턴은 잘못 붙여진 이름이라고 함
템플릿 팩토리 클래스 패턴이라고 생각하는게 좋을 듯 싶다.
팩토리 클래스가 하위 객체를 생성하는 메카니즘이 똑같을 때 사용한다. 팩토리 메소드 패턴의 목적은 상위 클래스가 create 할 때 받는 매개 변수를 통해 어떤 클래스를 생성할지 하위 클래스를 결정하여 생성해주는 것이다.
장점 + 생성자는 이름이 없어서 이게 뭘 생성하는지 몰랐다. 하지만 이름있는 함수를 호출하므로 이제 알 수 있다.
장점 + 싱글톤과 같이 중복되는 인스턴스에 대응하여 객체 생성 자체를 피할 수도 있다.
장점 + 입력 매개변수에 따라 다른 클래스를 반환 할 수 있다.
단점 - public, protected로 생성자를 만들지 않기 대문에 정적 팩토리 메소드를 적용한 클래스를 상속할 수 없다.
단점 - 뭐가 객체를 생성해주는 메소드인지 찾기 힘들다.
대표적으로 많이 사용하는 객체 생성 키워드- create : 인스턴스 생성
- from : 하나의 매개변수를 받아 인스턴스 반환
- of : 여러개 매개변수를 받아 인스턴스 반환
- valueOf : from, of의 더 자세한 버전
- getInstance, getType : 매개변수의 인스턴스를 반환
- newInstance, newType : 매개변수의 인스턴스를 반환, 매번 새로 생성을 보장
- 빌더 패턴
빌더 패턴은 연쇄 호출 후 build()하는 방식이다.
단 이 방식은 메소드 연쇄가 발생할 수 있다. (매소드 연쇄 = fluent API => 너무 길면 train wreck)
생성자의 매개변수가 많을 때 효율적이다. (적어도 4개 이상)
멤버변수의 유효성 검사후 오류일 경우 IllegalArgumentException 을 던질 수도 있다.
빈 객체를 만들고 내립다 setter를 사용하는 자바 빈즈 패턴과는 다르다. 자바 빈즈 패턴은 일관성이 무너진 상태다.
빌더를 가진 클래스를 상속받는 클래스를 생성하는 법도 익혀두자.
참고 : 제네릭에서는 this를 반환할 수 없다. 이 때 simulated self-type 구조를 이용하면 해결 가능하다.
Pizza ∋ Builder<T extends Builder<T>>
CombiPizza ∋ Pizza.Builder<Builder>
ShrimpPizza ∋ Pizza.Builder<Builder>
싱글톤
싱글톤 클래스의 생성자는 무조건 private 이여야한다.
싱글톤을 만드는 방법
- public 필드 방식
public static final Singleton INSTANCE = new Singleton();
+ 코드가 간결하다.
+ 싱글턴임이 확실히 보인다. - 정적 팩토리 메소드 방식
private static final Singleton INSTANCE = new Singleton();
public static Singleton getInstance() { return INSTANCE; }
+ 스레드 별로 다른 INSTANCE를 넘겨 줄 수 있게 할 수도 있다. (장점인가?)
+ 제네릭 싱글톤 패턴으로 변형할 수 있다.
+ 초기화 지연을 적용하게 할 수 도 있다. (그런데 초기화 지연은 프로그램의 복잡도만 올리고 성능도 그리 개선되지 않는다.) - Holder 방식
public static Singleton getInstance() { return SingletonHolder.INSTANCE; }
private static class SingletonHolder { public static final Singleton INSTANCE = new Singleton(); }
+ 보통 사용하는 방식이다.
- 리플렉션 API 를 이용한 공격이 존재한다. - 싱클톤을 클래스가 아니라 enum으로 만드는 방법
+ 리플렉션 API 를 이용한 공격도 방어가 된다.
+ 저자는 이 방법을 추천한다.
- 단 이 방법을 사용하면 싱글톤 상속은 안된다.
상황별 팁
- 어떤 클래스를 사용자가 객체로 만들어서 못쓰게 하고 싶으면 생성자를 private으로 지정해버려라
인터페이스나 추상 클래스로 만드는 것은 답이 아니다. 사용자가 해당 클래스를 상속해서 쓸 수도 있다. - new를 사용하는 것 보다. 의존 객체 주입 패턴을 적극 활용하라. 유연하고 테스트 용이한 코드가 될 것이다.
- 객체를 생성하는 것조차 자원 낭비라는 것을 유념해라
- 오토박싱을 피해라 이것도 객체를 만드는 행위다.(Long number -> long number)
- 객체를 다 사용하면 참조 해지를 통해 GC에 걸리도록 해라.
- 참조 해지 방법
- 참조 변수에 null을 할당한다.
- 참조 변수를 Scope이 다 되서 자동으로 해지 되게 한다.
- finalizer와 cleaner 사용을 피해라. C++의 파괴자와는 다른 개념이다. finalizer와 cleaner 의 호출은 gc에 의해 결정되므로 실행 시점, 실행 여부를 알 수 없다. 이들은 gc의 성능에도 영향을 주고 보안 이슈도 있다.
- 자바에는 close를 해야하는 자원이 너무 많다. 전통적인 방식에서는 try-finally를 많이 사용했다. 그러나 이는 너무 지저분하다 최근에는 try-with-resources 방식을 지원한다 이를 사용하자. 훨씬 읽기 쉽다. 단) 이 방식을 사용하려면 close해야하는 자원이 AutoCloseable을 반드시 implements 해야한다.
try-finally
InputStream in = new InputStream(srcPath)
try {
//...
}
finally {
if (in != null)
in.close();
}
try-with-resources
try (InputStream in = new InputStream(srcPath)){
//...
}
'[공부] 독서 > 이펙티브 자바 3판' 카테고리의 다른 글
[2019.03.17] 이팩티브 자바 3판 (5장 : 제네릭 사용시 - ) (0) | 2019.03.17 |
---|---|
[2019.03.10] 이펙티브 자바 3판 (4장 : 클래스, 인터페이스 설계) (0) | 2019.03.10 |
[2019.03.09] 이펙티브 자바 3판 (3장 : 공통 메소드) (0) | 2019.03.10 |