싱글톤(Singleton) 패턴이란?

이민형·2022년 8월 18일
0

디자인패턴

목록 보기
1/1
post-thumbnail

싱글톤(Singleton)이란?

어플리케이션이 실행될 때, 어떤 클래스가 한번만 메모리에 할당하고, 그 메모리에 인스턴스를 만들어 사용하는 디자인 패턴이다.

다시말해, 객체의 인스턴스가 오직 1개만 생성되는 패턴을 의미한다.

싱글톤(Singleton)의 장점

  1. 한번의 new 연산자를 통해 고정된 메모리 영역을 사용하기 때문에 추후 해당 객체에 접근 할 때, 메모리 낭비를 방지할 수 있다.
  2. 이미 생성된 인스턴스를 활용해서 속도 측면에도 이점이 있다.
  3. 전역으로 사용되는 인스턴스이기 때문에 다른 클래스 간에 데이터 공유가 쉽다.

싱글톤(Singleton)의 단점

  1. private 생성자를 가지고 있기 때문에 상속 할 수 없다.
  2. 서버환경에서는 싱글턴이 하나만 만들어지는 것을 보장하지 못한다.
  3. 싱글톤은 객체지향 프로그래밍에서 권장되지 않는 전역 상태를 만들 수 있기 때문에 바람직하지 못하다.

싱글톤(Singleton)의 생성방법

싱글톤의 가장 일반적인 생성 방식은 두 가지가 있다.
두 방식 모두 생성자는 private 로 감춰두고,
인스턴스에 접근할 수 있는 유일한 수단으로 public static 맴버를 하나 마련해 둔다.

1. public static 맴버가 final 필드인 방식

public class Singleton1{
    // public static final 맴버
    public static final Singleton1 s1 = new Singleton1();
    // private 생성자
    private Singleton1() { }

    public void doSomething1() { }
}

실행문

public class MainSingleton {
    public static void main(String[] args) {
        // public static 맴버가 final 필드인 방식의 Singleton
        Singleton1 chk1_s1 = Singleton1.s1;
        Singleton1 chk2_s1 = Singleton1.s1;
        // 둘이 주소값이 같은지 확인
        System.out.println(chk1_s1 == chk2_s1);
    }
}

결과

true


2. 정적 팩터리 메서드를 public static 맴버로 제공하는 방식

public class Singleton2 {
    // public static final 맴버
    public static final Singleton2 s2 = new Singleton2();
    // private 생성자
    private Singleton2() { }
    // 정적 팩토리 메서드
    public static Singleton2 getInstance(){ return s2; }

    public void doSomething2() { }
}

실행문

public class MainSingleton {
    public static void main(String[] args) {
        // 정적 팩터리 메서드를 public static 멤버로 제공하는 방식의 Singleton
        Singleton2 chk1_s2 = Singleton2.getInstance();
        Singleton2 chk2_s2 = Singleton2.getInstance();
        // 둘이 주소값이 같은지 확인
        System.out.println(chk1_s2 == chk2_s2);
    }
}

결과

true


public static 맴버가 final 필드인 방식의 장점

  1. 해당 클래스가 싱글턴임이 API에 명확히 드러난다.
  2. 간결하다.

정적 팩터리 메서드를 public static 맴버로 제공하는 방식의 장점

  1. getInstance() 메서드는 항상 같은 객체의 참조를 반환하므로, 다른 인스턴스는 만들어 지지 않는다.
  2. API를 바꾸지 않고도 싱글턴이 아니게 바꿀 수 있다.(getInstance() 에서 리턴하는 값을 바꾸면 된다.)
  3. 정적 팩터리 메서드를 제너릭 싱글턴 팩터리로 만들 수 있다.
  4. 정적 팩터리 메서드 참조를 Supplier로 사용할 수 있다.(호출한 곳으로 데이터를 리턴하는 역활을 한다.)



하지만!!!
이 두 방식에는 치명적인 단점이 존재한다.

만약 이 방법들을 직렬화에 사용한다면, 역직력화 할 때 새로운 인스턴스가 생겨서 싱글턴이 아니게 되어 버린다.
이것을 해결하려면 모든 인스턴스 필드를 직렬화 대상에서 제외(transient)한다 선언하고, readResolve 메서드를 제공해야 한다.

0개의 댓글