이것저것

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

Effective Java

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

nays111 2021. 4. 20. 16:41

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


[모든 클래스가 인스턴화가 필요한 것은 아니다.]

정적 메서드와 필드만을 담을 클래스는 쓸모가 있다. java.lang.Math, java.util.Array 처럼 기본 타입값이나 배열에 관련된 메서드들을 모을 수 있고, java.util.Collections 처럼 특정 인터페이스 구햔 객체를 생성해주는 메서드를 모아 놓을 수도 있다.

 

final 클래스와 관련된 메서드를 모을 때도 마찬가지다. 이를 상속하여 하위클래스에 메서드를 넣는 것이 불가능하기 때문이다. (애초에 상속 불가능)


[인스턴스화를 막으려면?]

클래스 내부에 정적 메서드만 있고, 유틸리티 기능을 강조하기 위한 클래스를 하나 만들어보았다.

 

유틸리티 클래스
  • 인스턴스 메서드와 인스터스 변수를 일절 제공하지 않고, 정적 메서드와 변수만을 제공하는 클래스를 뜻한다.
  • 유틸리티 클래스는 인스턴스로 만들어 쓰려고 설계한 게 아니다.
  • 클래스 본래의 목적인 '데이터와 데이터 처리를 위한 로직의 캡슐화'를 실행하는 것이 아닌,'비슷한 기능의 메서드와 상수를 모아서 캡슐화'한 것이 유틸리티 클래스이다.
public class DateUtility {
    private static String FULL_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss.SSS";

    // 생성자 없음

    public static String convertDateToString(Date date) {
        return new SimpleDateFormat(FULL_DATE_FORMAT).format(date);
    }
}

(컴파일러는 생성자를 명시하지 않는 경우에, 자동으로 기본 생성자 생성)

public void someMethod() {
    // 이렇게 사용하길 기대했으나!
    DateUtility.convertDateToString(new Date());
    
    // 누군가는 이렇게 사용할 수도
    DateUtility dateUtility = new DateUtility();
    String formattedToday = dateUtility.convertDateToString(new Date());
}

이런 인스턴스화를 막기 위해 private 생성자를 추가해주면 된다.

class DateUtility {
    private DateUtility() {
        /**
         * 클래스 내부에서도 호출이 안되도록 막는다.
         */
        throw new AssertionError(); //행여나 클래스 내부에서 실수로라도 생성를 호출하는 것을 막기 위해
    }

    // 생략
}

public class PrivateConstructorTest {
    public static void main(String[] args) {
        // DateUtility() has private access in DateUtility
        DateUtility dateUtility = new DateUtility();
    }
}

생성자를 private으로 만들면, 외부에 공개하지 않기 때문에 상속도 불가능해진다.

 

즉 private 생성자를 추가함으로써, 클래스의 인스턴스화를 막을 수 있다.

Comments