ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Effective Java - 2장. 생성과 파괴(1/3)
    Computer - Java 2022. 12. 23. 07:36

    item 1. 생성자 대신 정적 팩터리 메서드를 고려하라

    item 2. 생성자에 매개변수가 많다면 빌더를 고려하라

    item 3. private 생성자나 열거 타입으로 싱글턴임을 보증하라

    item 4. 인스턴스화를 막으려거든 private 생성자를 사용하라

    item 5. 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라

    item 6. 불필요한 객체 생성을 피하라

    item 7. 다 쓴 객체 참조를 해제하라

    item 8. finalizer와 cleaner 사용을 피해라

    item 9. try-finally보다는 try-with-resources를 사용하라

     

    item 1. 생성자 대신 정적 팩터리 메서드를 고려하라.

    무조건적으로 정적 팩터리 메서드를 사용하라기보다는 "고려"하라는 것이다. 그만큼 장단점도 명확한 편이다

    장점

    (1) 이름을 가질 수 있다 - 조금 더 직관적으로 무엇을 하는 메서드인지 알 수 있다

    (2) 호출될 때 마다 인스턴스를 새로 생성하지는 않아도 된다 - ex. Boolean.TRUE/FALSE, 플라이웨이트 패턴

    (3) 반환 타입의 하위 타입 객체를 반환할 수 있는 능력이 있다

       +) Java 8부터 인터페이스에 static 메서드를 가질 수 있게 되었다(비록 public 정적 멤버만 허용되지만)

    (4) 입력 매개변수에 따라 매번 다른 클래스의 객체를 반환할 수 있다(자식 객체이기만 하면)

    (5) 정적 팩터리 메서드를 작성하는 시점에는 반환할 객체의 클래스가 존재하지 않아도 된다

      - 아직 이해안됨(...) 다른 몇몇 블로그를 봐도 다들 어려워하는 것 같다

     

    단점

    (1) 상속을 하려면 public이나 protected 생성자가 필요함 - 정적 팩터리 메서드만 제공하면 하위 클래스를 만들 수 없다

    (2) 정적 팩터리 메서드는 프로그래머가 찾기 힘들다 - 흔히 사용되는 명명 방식이 있음

    • from - 매개변수 하나를 받아서 해당 타입의 인스턴스 반환하는 형변환 메서드
    • of - 여러 매개변수를 받아 적합한 타입의 인스턴스를 반환하는 집계 메서드
    • valueOf - from과 of의 조금 더 자세한 버젼
    • instance/getInstance - 매개변수로 명시한 인스턴스 반환 but 같은 인스턴스임을 보장하지는 않음
    • create/newInstance - instance/getInstance와 같으나 매번 새로운 인스턴스를 생성해 반환함을 보장
    • getType - getInstance와 같지만, 생성할 클래스가 아니라 다른 클래스에 팩토리 메서드를 정의할 때
    • newType - newInstance와 같지만, 생성할 클래스가 아니라 다른 클래스에 팩토리 메서드를 정의할 때
    • type - getType와 newType의 간단한 버전

    이텔릭체로 표현된 Type는 팩토리 메서드가 반환할 객체 타입이다(ex. getList, newBufferedReader)

     

     

    (작성중)

     

     

    item 2. 매개변수가 많다면 빌더를 고려하라

    기본적으로 디자인 패턴에 대해 배우게 되면 빌더 패턴에 대해서 공부하는데, 이것을 조금 자세히 설명했다고 보면 된다.

     

    1. 점층적 생성자 패턴 - 단점 : 매개변수 개수가 많아지면 클라이언트 코드를 작성하기나 읽기 어려움

    2. setter를 통한 초기화(자바빈즈 패턴) - 단점 : 기본값이 없어 필수로 지정해야 하는 경우 일관성이 무너진 상태 + final의 경우 초기화 불가

    3. Builder Pattern(내부에 static builder class 만듦 + 생성자를 private하게) - 좋은 예시. 계층적으로 설계된 클래스와 쓰기 좋음(abstract로 build()와 self()를 추상화한 뒤 하위 클래스에서 구현)

    * 빌더 패턴 단점 : 성능이 민감할 때 문제(객체를 두 개 만듦), 매개변수 4개 이상 되어야 값어치를 함

    하지만 요즘 매개변수가 4개 넘는 것은 일이 아니기에 괜히 생성자를 쓰다가 빌더 패턴으로 전환하지 말자(처음부터 빌더 패턴 쓰려면 쓰자)

     

    item 3. private 생성자나 열거 타입으로 싱글턴임을 보증하라

    방법 1 - public static final 사용 - 리플렉션 API에 취약(private 생성자 호출 가능), 하지만 간결함/명확성의 장점

    방법 2 - private static final 필드 + getInstance - 후술할 여러 장점이 있지만...?

    • 마음이 바뀌면 호출하는 스레드별로 or 제네릭마다 다른 인스턴스를 넘겨줄 수 있다
    • 정적 팩터리의 메서드 참조를 공급자로 사용할 수 있다(ex. Elvis::getInstance를 Supplier<Elvis>로)

    방법 1, 2는 모두 단점이 있는데, 직렬화 후 역직렬화 시 두 개 이상의 객체가 만들어 질 수 있다는 점이다.

    참고로 직렬화는 JVM간 통신을 위해 객체를 byte코드로 바꾸는 것을 말하며, 역직렬화는 byte코드를 객체로 바꾸는 것을 말한다.

    모르면 여기에 설명이 잘 되어있다 - https://go-coding.tistory.com/101

    직렬화 후 역직렬화 시 하나의 객체임을 보장하기 위해서는 모든 인스턴스 필드를 일시적(transient)이라고 선언하고 readResolve 메서드를 제공해야 한다고 하는데 자세한 건 나중에 자세히 알아보고(아이템 89) 무튼 그래서 저자가 추천하는 방법은,

     

    방법 3 - 원소가 하나인 열거 타입을 선언(저자는 이것을 추천)

    enum의 특성은 다음과 같다

    1. 상수들만 모아놓은 클래스로 생성자, 메서드를 가질 수 있다.

    2. private한 생성자를 가진다.

    3. enum타입은 고정된 상수들의 집합으로써, 런타임이 아닌 컴파일타임에 모든 값을 알고 있어야 합니다. 즉 다른 패키지나 클래스에서 enum 타입에 접근해서 동적으로 어떤 값을 정해줄 수 없음.

    4. 상속 불가

     

    이 4가지 특징이 싱글턴이랑 거의 동일하기 때문에 enum을 추천하였다.

    enum 특성은 여기서 퍼왔습니다

     

    [이펙티브 자바] private 생성자나 열거 타입으로 싱글턴임을 보증하라

    싱글톤 : 인스턴스를 오직 하나만 생성할 수 있는 클래스 싱글톤 패턴을 왜 사용할까? 인스턴스를 오직 하나만 생성하므로서 객체를 여러번 생성할 필요가 없고 객체를 공유할 수 있음. 스프링

    jgrammer.tistory.com

     

     

Designed by Tistory.