티스토리 뷰

반응형

싱글톤이란, 하나의 인스턴스만 생성하도록 구현하는 것을 말한다.

 

기본적인 설계

image

 

요구사항

  • 개발 중 시스템에서 스피커에 접근할 수 있는 클래스를 만들어달라.

 

싱글톤 객체 정의

public class SystemSpeaker {
  static private SystemSpeaker instance;
  private int volume;

  private SystemSpeaker() {
    volume = 5;
  }

  //하나의 인스턴스만을 만들기 위한 메소드
  public static SystemSpeaker getInstance() {
    if(null == instance) {
      return instance = new SystemSpeaker();
    }
    return instance;
  }

  public int getVolume() {
    return volume;
  }

  public void setVolume(int volume) {
    this.volume = volume;
  }
}

Main

public static void main(String [] args) {
  SystemSpeaker systemSpeaker1 = SystemSpeaker.getInstance();
  SystemSpeaker systemSpeaker2 = SystemSpeaker.getInstance();

  System.out.println("systemSpeaker1 : " + systemSpeaker1);
  System.out.println("systemSpeaker2 : " + systemSpeaker2);
}

실행결과

image

  • 두개의 객체는 같은 주소를 가지고 있는 것을 확인할 수 있다.

 


리플렉션을 사용해서 싱글톤 깨버리기

  • Java에서는 위와 같은 싱글톤 정의를 깨버릴 수 있는 경우도 있다.
public static void main(String [] args) throws ClassCastException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, ClassNotFoundException, NoSuchFieldException {
  SystemSpeaker systemSpeaker1 = SystemSpeaker.getInstance();
  SystemSpeaker systemSpeaker2 = SystemSpeaker.getInstance();

  System.out.println("systemSpeaker1 : " + systemSpeaker1);
  System.out.println("systemSpeaker2 : " + systemSpeaker2);

  //리플렉션을 활용하여 싱글톤 깨버리기
  Class<?> speakerClass = Class.forName("com.pattern.ch05_singleton.SystemSpeaker");
  Constructor<?> constructor = speakerClass.getDeclaredConstructor();
  //접근 제한자에 상관없이 모두 접근 가능
  constructor.setAccessible(true);
  SystemSpeaker systemSpeaker3 = (SystemSpeaker) constructor.newInstance();
  System.out.println(systemSpeaker3);

}
  • 소스에서 보는 봐와 같이 reflection을 활용하여 해당 클래스의 생성자 메소드에 접근하여 아예 새로운 인스턴스를 만들 수 있다.

image

  • 그로 인해 정말 안정적인 싱글톤을 생성하고자 한다면 enum을 사용하여 싱글톤 객체를 만들 수 있도록 해야한다.

 

 

Enum 사용

public enum EnumSystemSpeaker {
  INSTANCE;

  private int volume = 5;

  public int getVolume() {
    return volume;
  }

  public void setVolume(int volume) {
    this.volume = volume;
  }
}

//Main
//enum 사용
public static void main(String [] args) {
  System.out.println(System.identityHashCode(EnumSystemSpeaker.INSTANCE.getClass()));
    System.out.println(System.identityHashCode(EnumSystemSpeaker.INSTANCE.getClass()));
}

image

  • 10진수로 된 메모리 주소가 동일하는 것을 확인할 수 있다.
  • Enum을 사용할 시 스레드 세이프하고 Serialization을 스스로 해결하며, reflection에서도 안정성을 보장하는 특징을 가지고 있다.
반응형
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함