ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • private/public, static, final
    공부 이야기/JAVA 2024. 1. 22. 14:23

    <기본 개념>

    1. private : 선언한 클래스 내부에서만 사용할 수 있도록 접근을 제어

    2. public : 선언한 클래스 외부에서도 사용할 수 있도록 개방

    3. static : 변수 혹은 객체에 대해 한 번만 생성할 수 있도록 함

    4. final : final로 선언된 변수, 객체에 대해서 값 변경을 할 수 없도록 제어 (Immutable)

     

    <싱글톤과 적용>

    동일한 내용에 대해 빈번하게 참조되는 객체가 있다고 가정했을 때 참조할 때마다 객체를 생성하는 것은 비효율적일 수도 있고 더 나아가서 성능을 떨어트릴 수도 있다.

    이 때 static 키워드를 사용하면 단 한 번의 인스턴스 생성이 이뤄지며 구조적 비효율을 개선하고 성능을 최적화할 수 있다.

    하지만 싱글톤 패턴을 사용했을 때 발생할 수 있는 Thread-safety 문제가 존재한다.

    Thread-unsafe code

    위 코드에서 동시에 여러 Thread가 null 여부를 확인할 때 의도치 않게 두 개의 객체를 반환할 수 있다.

    그렇다고 인스턴스 선언만 해둔 상태인 DownState 객체를 new 키워드로 생성까지 한다면 초기 Memory-load에 부하를 일으킬 수 있다.

    아마도 저 code는 lazy-load를 의도한 것 같다.

    그렇다면 lazy-load와 Thread-safe 모두 만족시킬 수 있는 방법은 무엇일까?

    DownState 클래스 내부에 private static으로 인스턴스 반환용 내부 클래스를 생성한 후

    private static final으로 선언한 객체를 new 키워드로 생성한다.

    그리고 null 체크하는 대신에 내부 클래스의 static으로 선언한 객체를 리턴해주면 된다.

    /* 내부 클래스 생성 */

    private static StaticHolder {

         private static final DownState INSTANCE = new DownState();

    }

     

    /* 새로 만든 getInstance() 메소드 */

    public static DownState getInstance() {

        return StaticHolder.INSTANCE;

    }

     

    < Spring Bean >

    Spring에서 Bean으로 관리하는 객체들은 기본적으로 싱글톤으로 구현되어 있기 때문에 Thread-unsafety 한 점에 대해 알고 있어야 하며

    Bean으로 등록된 객체들은 상태가 변할 수 있는 내부 변수를 갖지 않도록 설계해야한다.

    앞서 언급한 방식처럼 내부 변수(혹은 객체)를 final로 선언한 후, 직접 참조하지 않고 getter를 이용해서 return해야 한다.

    생성자 방식으로 의존성을 주입할 때도 의존할 객체를 선언할 때 앞에 private final 키워드가 붙는 이유기도 하다.

     

     

    <getter/setter>

    참조할 클래스의 멤버 변수에 접근할 때 . 키워드를 사용하지 않고 getter/setter를 사용하는 이유는 뭘까

    참조할 클래스가 다른 곳에서도 사용될 경우 의도치 않게 수정되어 난장판이 발생할 수 있기 때문이라고 한다.

    근데 사실 사용할 클래스에서 별도의 변수나 DTO, VO와 같은 객체를 사용할 수 있음에도 불구하고 말이다.

    쉽게 말해서 조심스럽게 사용하면 되는 부분이 아닌가는 생각이 들 수는 있다.

    그러나 직관적이지 않고 기능 분리가 명확히 구분되지 않은 코드는 실수를 범할 수도 있고 설계 누락의 위험을 가진다.

    또한, 개방/폐쇄 원칙이랑 연관이 깊은데 이론적으로만 접근했을 경우 와닿지가 않을 수 있다.

    이 문제는 마치 코드를 하나의 클래스에서 쭉 늘여서 작성하는 것보다 패키지로 관리해서 명확히 구분하는 것과 같은 이치로 생각해볼 수 있다.

    암튼 결론은 변수는 모두 private으로 선언하여 직접적인 접근을 허용하지 않도록 한 후,

    getter/setter에 대해서만 public으로 선언해서 사용할 수 있도록 설계해야 한다는 점이다.

     

     

    '공부 이야기 > JAVA' 카테고리의 다른 글

    equals() 메소드 내부 동작  (0) 2021.09.05
    인터페이스식 프로그래밍  (0) 2021.09.02
    JAVA 8 - 람다식  (0) 2020.11.08
Designed by Tistory.