모르지 않다는 것은 아는것과 다르다.

Books

이펙티브 자바 2장 (객체 생성과 파괴)

채마스 2022. 5. 30. 23:49

[아이템 1] 생성자 대신 정적 팩터리 메서드를 고려하라

장점

  • 이름을 가질 수 있다.
public class Bike {
    private int wheelCount;
    private String color;

    private Bike(int wheelCount, String color) {
        this.wheelCount = wheelCount;
        this.color = color;
    }

    public static Bike createBike(String color) {
        return new Bike(2, color);
    }

    public static Bike createTricycle(String color) {
        return new Bike(3, color);
    }
}
  • 매번 인스턴스를 새로 만들지 않아도 된다.
public class Bike {
    private int wheelCount;
    private String color;

    private static final Bike redBike = new Bike(2, "red");
    private static final Bike betaRobot = new Bike(2, "blue");

    public Bike(int wheelCount, String color) {
        this.wheelCount = wheelCount;
        this.color = color;
    }

    public static Bike getInstanceRedBike() {
        return redBike;
    }

    public static Bike getInstanceBlueBike() {
        return betaRobot;
    }
}
  • 휠이 2개이고 색이 레드와 블루인 경우 굳이 새로 인스턴스를 만들 필요없다.
  • 반환 타입의 하위 타입 객체를 반환할 수 있는 능력이 있다.
    • 반환 값을 하위 클래스로 설정하면 되기 때문이다.
  • 입력 매개변수에 따라 매번 다른 클래스의 객체를 반환할 수 있다.
    • 매개변수를 원하는대로 설정할 수 있기 때문이다.
  • 정적 팩토리 메소드 작성 시점에는 반환 객체의 클래스가 존재하지 않아도 된다.

단점

  • 상속을 하려면 public이나 protected 생성자가 필요하니 정적 팩토리 메소드만 제공하면 하위 클래스를 만들 수 없다.
  • 생성자처럼 명확히 드러나지 않는다.

정적 팩터리 메서드의 메소드명을 짓는 일반적인 규약

  • from: 매개변수를 받아서 해당 타입의 인스턴스를 반환
    • Date date = Date.from(instant);
  • of: 여러 매개변수를 받아서 인스턴스 반환
    • Set cards = EnumSet.of(JACK, QUEEN, KING);
  • valueOf: from과 of의 더 자세한 버전
    • BigInteger prime = BigInteger.valueOf(Integer.MAX_VALUE);
  • instance / getInstance: 인스턴스를 반환하지만, 같은 인스턴스임을 보장하지 않는다.
    • StackWalker luke = StackWalker.getInstance(options);
  • create / newInstance: 매번 새로운 인스턴스를 생성해 반환한다.
    • Object newArray = Array.newInstance(classObject, arrayLen);
  • getType: getInstance와 같으나 생성할 클래스가 아닌 다른 클래스에 팩터리 메서드를 정의할 때 사용
    • FileStore fs = Files.getFileStore(path);
  • newType: newInstance와 같으나 생성할 클래스가 아닌 다른 클래스에 팩터리 메서드를 정의할 때 사용
    • BufferedReader br = Files.newBufferedReader(path);
  • type: getType과 newType의 간결한 버전
    • List litany = Collections.list(someList);

 

[아이템 3] private 생성자나 열거 타입으로 싱글턴임을 보증하라

private 생성자와 public static 필드

public class Elvis {
    public static final Elvis INSTANCE = new Elvis();
    private Elvis() { }

    public void leaveTheBuilding() { }
}

private 생성자와 public static 정적 팩토리 메서드

public class Elvis {
    private static final Elvis INSTANCE = new Elvis();
    private Elvis() { }

    public static Elvis getInstance() {
        return INSTANCE;
    }

    public void leaveTheBuilding() { }
}

원소가 하나인 Enum 타입 선언

public enum Elvis {
    INSTANCE;

    public void sleep() { }
}

 

[아이템 4] 인스턴스화를 막으려거든 private 생성자를 사용하라

  • 유틸성 클래스는 보통 인스턴스화해서 쓰기보단, static method 들로 구성하고 많이 쓴다.
  • 하지만 java 컴파일러는 생성자를 명시하지 않으면 컴파일러가 자동으로 기본 생성자를 만들어낸다.
  • 따라서 인스턴스화를 막으려면 private 생성자를 명시적으로 생성해주어야 한다.
  • 혹시라도 클래스 내부에서 생성자를 호출하지 않도록 오류를 던지는 것도 좋다.
public class BikeUtils {
    private BikeUtils() {
        throw new AssertionError();
    }

    // static method (유틸성)
    public static <T> T convertObject(..) {...}
}

 

[아이템 5] 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라

  • 사용하는 자원에 따라 동작이 달라지는 클래스에는 정적 유틸리티 클래스나 싱글톤 방식이 적합하지 않다.
  • 이럴 때는 인스턴스를 생성할 때 생성자, static factory method, builder로 필요한 자원을 넘겨주는 방식이 좋다.
  • 이것을 의존객체 주입 패턴 이라 한다.
  • 잘못된 예시
public class SpellChecker { 
    private final Lexicon dictionary = new KoreanDic(); 
    private SpellChecker() {} 
    public boolean isValid(String word) { } 
    public List<String> suggestions(String typo) { } 
}
  • 올바른 예시1
public class SpellChecker { 
    private final Lexicon dictionary;
    public SpellChecker(Lexicon dictionary) { 
        this.dictionary = dictionary; 
    }
    public boolean isValid(String word) { } 
    public List<String> suggestions(String typo) { } 
}
  • 올바른 예시2 (Factory를 넘겨주는 방식)
public SpellChecker(Supplier<? extends Lexicon> dicFactory) { 
    this.dictionary = dicFactory.get(); 
}

 

 

REFERENCES

  • 이펙티브 자바 2장

'Books' 카테고리의 다른 글

클린코드 10장  (0) 2022.04.30
클린코드 9장 (단위 테스트)  (0) 2022.04.30
클린코드 8장  (0) 2022.04.23
클린코드 6장 (객체와 자료구조)  (0) 2022.04.23
클린코드 4장 (주석)  (0) 2022.04.23