Programming/Java

[Youtube][이팩티브 자바] #4 인스턴스를 못만들게 하고 싶다면?

bisi 2020. 5. 20. 09:37

백기선님의 유투브 강의 내용을 정리하였습니다.

 

백기선님 Github 바로가기

Youtube 바로가기

 

 

강의내용 필기 


주제 4. private 생성자로 noninstantiability를 강제할 것 

 

static 메서드와 static 필드를 모아둔 클래스를 만든 경우 해당 클래스를 abstract로 만들어도 인스턴스를 만드는 걸 막을 순 없다. 상속 받아서 인스턴스를 만들 수 있기 때문이다.

 

 

static 메서드와 static 필드를 모아둔 클래스를 만든 경우

  • utility 클래스를 이렇게 많이 만든다. utility 클래스는 인스턴스를 만들 필요가 없기 때문에, abstact로 만들어서 강제할 수 있다. 
  • static클래스는 너무 많이 쓰면 안좋은 평판이 있다. (하지만 유효한 경우도 있다. Math, Array, Collections 같은 경우)
  • 사용자들 입장에서는 아래처럼 사용하길 바란다.
public class UtilClass {

    public static String getName() {
        return "log";
    }

    public static void main(String[] args) {
    	//아래처럼 사용하기보다는 
        //UtilClass utilClass = new UtilClass();
        
        //아래처럼 사용하길 원함.
        UtilClass.getName();

    }

}

 

  • 1차적으로 막을 수 있는 방법이 abstract class를 만드는 것이다. 
public abstract class UtilClass {

    public static String getName() {
        return "log";
    }

    public static void main(String[] args) {    	
        UtilClass utilClass = new UtilClass();
        
    }

}

 

  • 하지만 추상 클래스는 아래처럼 상속 받아와서 사용하는 경우는 다시 사용이 가능하다. 
public abstract class UtilClass {

    public static String getName() {
        return "log";
    }
    
    static class AnotherClass extends Utilclass{
    
    }

    public static void main(String[] args) {
    	//가져올 수 있지만 밑에 있는 메소들르 못가져오므로 의미 없다. 
        AnotherClass anotherClass = new AnotherClass();        
        

    }

}

 

  • 책에서 권고 하고 있는 방법은 명시적으로 private 생성자를 추가하는 것이다.

 

public class UtilityClass {
    // Suppress default constructor for noninstantiability
    private UtilityClass() {
        throw new AssertionError();
    }
}

 

  • AsseionError는 꼭 필요하진 않지만, 그렇게 하면 의도치 않게 생성자를 호출한 경우에 에러를 발생시킬 수 있고, private 생성자기 때문에 상속도 막을 수 있다. 
  • 생성자를 제공하지만 쓸 수 없기 때문에 직관에 어긋나는 점(사실을 못쓰는 것)이 있는데, 그 때문에 위에 코드처름 주석을 추가하는 것이 좋다. 
  • 부가적으로 상속도 막을 수 있다. 상속한 경우에 명시적으로든 암묵적이든 상위 클래스의 생성자를 호출해야 하는데, 이 클래스의 생성자가 private이라 호출이 막혔기 때문에 상속을 할 수 없다. 

 

하지만 현실은 .......

하지만 spring util을 살펴보면 굳이 private으로 적용하는 방법으로 구현하진 않았다. 

 

음.. 백기선님은 abstract를 만드는 것만 해도 충분하다고 한다.

누가 상속을 해서 만든다 하더라도 어차피 사용하지 못하기 때문이다. 

현실적으로는 abstract를 써도 util 클래스를 instance로 만들어지는 것을 방지 하는데 충분하다. 

(String 자바 다큐먼트만 봐도 uili클래스는 대부분 abstract로 만들어져 있다.)