본문 바로가기
쿤즈 Dev/Desing pattern

[Design Pattern] Singleton(1) : 싱글톤! 하나의 인스턴스로 관리

by :)Koon 2021. 11. 19.

이번 포스팅은 Java를 이용한 Design Pattern 중 하나를 알아보도록 하겠습니다. Java에는 여러 가지 디자인 패턴들이 있습니다. 디자인 패턴들은 자바 소스코드를 설계하는 방법을 이야기합니다.

여러 가지 디자인 패턴들 중에서 오늘은 Singleton(싱글톤)에 대해서 알아보도록 하겠습니다.


Design Pattern: Singleton (싱글톤)

애플리케이션을 실행할 때 여러 개의 인스턴스를 만들어서 사용하게 됩니다. 인스턴스라 함은 사용자가 만들거나 만들어진 클래스들이 실제 메모리에 올라가고 사용할 수 있도록 주소가 할당된 상태를 의미합니다. 그래서 Java(자바) 언어에서는 클래스를 인스턴스로 만들기 위해서 new 연산자를 이용합니다.

 

만약 동일한 클래스에서 변하지 않는 동일한 정보들을 여러곳에서 사용하고자 한다면 어떨까요?

불필요한 객체생성을 줄이고 단 하나의 인스턴스만을 사용하기 위한 방법이 바로 싱글톤 디자인 패턴입니다. 오직 하나의 클래스 인스턴스만 갖도록 보장하고 전역적으로 접근이 가능하도록 합니다.

인스턴스를 단 하나만 사용한다면 메모리의 효율성도 좋고 모두 동일한 인스턴스를 사용하기 때문에 모두 같은 값에 접근이 가능하다는 장점이 있습니다. 그렇다면 싱글톤은 어떻게 구현하고 사용하는지 알아볼게요.


Design Pattern: Singleton 예제

우선 싱글톤 예제를 보기 전에 아래 예제를 먼저 보도록 할게요.


예제 1. 새로운 인스턴스 생성

package singleton.example_1;

public class SingletonTest {
    public static void main(String[] args) {
        Object obj1 = new Object();
        Object obj2 = new Object();

        System.out.println("obj1 = " + obj1);
        System.out.println("obj2 = " + obj2);
    }
}

위 예제에서 결과를 출력하면 서로 다른 값이 나오는 것을 확인할 수 있습니다. 왜냐하면 new를 이용해서 서로 다른 인스턴스를 만들었기 때문입니다.

obj1 = java.lang.Object@72ea2f77
obj2 = java.lang.Object@33c7353a

이때 @ 뒤에 나오는 문자가 할당된 메모리 주소를 의미입니다. 이 메모리 주소가 현재는 다르다는 사실을 알 수 있습니다. 즉, new를 이용하면 새로운 Object가 메모리에 할당되고 그 주소를 가지고 있다고 생각하시면 됩니다. 그렇다면 우리가 사용할 인스턴스를 만들어 볼게요.


예제 2. 싱글톤 인스턴스 1

우선 Singleton 클래스를 만들어 줍니다.

package singleton.example_2;

public class Singleton {
    private static Singleton instance = null;

    private Singleton() {}

    public static Singleton getInstance() {
        return new Singleton();
    }
}

클래스 내부에서 사용할 변수이므로 private static으로 선언해주고 값은 null로 초기화하는 코드를 작성했습니다. 다음은 parameter가 없는 생성자(Constructor)는 private으로 선언하여 외부에서 사용할 수 없도록 만들어 주었습니다. 이 코드를 넣은 이유는 아래 예제에서 확인해 보실 수 있습니다.

 

마지막으로 static 메서드를 만들어 주었으며 getInstance()를 호출할 경우 새로운 new 인스턴스를 호출하도록 하였습니다. 실행 예제를 볼게요.

package singleton.example_2;

public class SingletonTest {
    public static void main(String[] args) {
//        Singleton singleton = new Singleton();
        Singleton singleton1 = Singleton.getInstance();
        Singleton singleton2 = Singleton.getInstance();

        System.out.println("singleton1 = " + singleton1);
        System.out.println("singleton2 = " + singleton2);
    }
}

main 메서드 상단은 주석으로 처리해 두었는데요. 이는 클래스에서 생서자를 private으로 선언했기 때문에 new를 이용해서 인스턴스를 생성할 수 없게 만든 것입니다. 즉, Singleton이라는 클래스를 사용하고 싶다면 반드시 getInstance()라는 메서드를 사용하도록 만든 것입니다.

 

이렇게 singleton1과 singleton2를 만들었습니다. 이 두 인스턴스의 값은 어떨까요? 눈치채셨겠지만 정답은 "다르다"입니다.

singleton1 = singleton.example_2.Singleton@33c7353a
singleton2 = singleton.example_2.Singleton@681a9515

클래스 이름만 Singleton이며 역할은 getInstance() 메서드 내부에서 매번 새롭게 new를 이용해서 인스턴스를 만들어줍니다. 따라서 같지 않습니다.

 

그럼 이제 정말 싱글톤의 역할을 하기 위한 메서드를 만들어 주겠습니다.


예제 3. 싱글톤 인스턴스 2

이번에는 Singleton 클래스를 변경해 보도록 하겠습니다.

package singleton.example_3;

public class Singleton {
    private static Singleton instance = null;

    private Singleton() {}

    public static Singleton getInstance() {
        if(instance == null)
            instance = new Singleton();

        return instance;
    }
}

대부분은 똑같지만 getInstance() 메서드 구현부의 차이가 있습니다.

이번에는 instance를 확인합니다. 최초 instance의 값이 null인지를 판단하고 값이 null이라면 아직 객체 생성을 하지 않은 것이기 때문에 new를 이용해서 인스턴스를 생성합니다. 이렇게 생성한 instance를 결과로 리턴해줍니다.

 

만약 두 번째 getIntance() 메서드의 호출이 있다면 어떨까요?

package singleton.example_3;

public class SingletonTest {
    public static void main(String[] args) {
        Singleton singleton1 = Singleton.getInstance();
        Singleton singleton2 = Singleton.getInstance();

        System.out.println("singleton1 = " + singleton1);
        System.out.println("singleton2 = " + singleton2);
    }
}

첫 번째 인스턴스 생성에서 Singleton 클래스 내부의 instance 변수에는 이미 값을 가지고 있게 됩니다. 따라서 두 번째 getInstance() 메서드의 호출이 발생하면 기존에 있던 값이 그대로 반환되기 때문에 new를 사용하지 않게 됩니다.

 

결과를 볼게요.

singleton1 = singleton.example_3.Singleton@33c7353a
singleton2 = singleton.example_3.Singleton@33c7353a

어떻신가요? 동일한 인스턴스임을 확인하셨나요?

 

이렇게 애플리케이션에도 동일한 인스턴스 하나만을 생성해서 사용하고 싶을 때 사용하는 디자인 패턴이 바로 싱글톤 패턴입니다.


이번 포스팅에서는 디자인패턴 첫 번째로 Singleton (싱글톤) 패턴에 대해서 알아보았습니다. 싱글톤 패턴을 사용하면 좋은 점들이 많이 있습니다. 우선 메모리를 아낄 수 있다는 장점과 모두 하나의 인스턴스를 바라보기 때문에 동일한 결과를 보장받을 수 있다는 장점이 있습니다.

 

여기서 동일한 결과를 보장받을 수 있다고 했는데요. 사실 싱글톤 패턴으로 사용하면 현재 구조에서는 동일한 값을 보장받을 수 없습니다. 바로 동시성 문제인데요. 이 부분에 대해서는 다음 포스팅에서 조금 더 자세하게 알아보도록 하겠습니다.

댓글