본문 바로가기

1.프로그래밍/Java

[Java] Singleton Pattern 이란? (디자인 패턴)

728x90
반응형

[Java] Singleton Pattern 이란? (디자인 패턴)

디자인 패턴이란?

디자인 패턴이란 소프트웨어를 설계할 때 특정 맥락에서 자주 발생하는 문제들을 해결하기 위한 패턴들을 정의해 놓은 것이다.


그 중 GoF 디자인 패턴이 가장 유명하며, GoF 디자인 패턴은 크게 3가지로 분류된다.


객체의 생성과 관련된 Creational Pattern 생성패턴,
클래스나 객체를 조합하여 더 큰 구조를 만드는 Structural Pattern 구조패턴,
클래스 혹은 객체 사이의 책임분배에 대한 Behavioral Pattern 행위패턴이 존재한다.

그 중 Singleton Pattern은 생성패턴에 속한다.

Singleton Pattern 이란?

생성자가 여러 차례 호출되더라도 실제로 생성되는 객체는 하나이고 최초 생성 이후에 호출된 생성자는 최초의 생성자가 생성한 객체를 리턴한다. 이와 같은 디자인 유형을 싱글턴 패턴이라고 한다.


즉, 객체의 인스턴스가 오직 1개만 존재한다는 것이 싱글톤 패턴이다.


싱글톤 패턴을 사용하게 되면 한번의 객체 생성으로 재사용하기 때문에 메모리가 절약된다.
또한 싱글톤 패턴을 사용한 인스턴스는 전역으로 설정하여 다른 클래스간 공유가 쉽다.

Code

먼저 Singleton Pattern을 보기 전에 일반적으로 객체를 생성하는 방식을 먼저 보겠다.

public class Test {
    public static void main(String[] args) {
        System.out.println("출력")
        for (int i = 0; i < 10; i++) {
            Test2 test2 = new Test2();
            System.out.println(test2.toString());
        }
    }    
}

class Test2{

    private int nextCount = 0;

    public Test2(){};

    public int nextCount(){
        return nextCount++;
    }
}

/*
출력
Test2@123772c4
Test2@2d363fb3
Test2@7d6f77cc
Test2@5aaa6d82
Test2@73a28541
Test2@6f75e721
Test2@69222c14
Test2@606d8acf
Test2@782830e
Test2@470e2030
*/

일부러 toString()메서드를 이용하여 객체의 주소값을 찍어보았다.
위의 출력값과 같이 모두 다른 주소값이 생성되었다.


즉, 모두 다른 객체라는 것이다.
그렇다면 메모리는 각 객체마다 할당되었을 것이며,
만약 동일한 객체를 이용해 nextCount()라는 메서드를 이용해 값을 증가시키고자 할때,
위와 같이 각각 다른 클래스에서 생성하게 되면 count변수는 초기화되어 증가될 것이다.


그렇다면 이제 싱글톤으로 객체를 생성하는 방법을 보자.


Singleton.class

public class Singleton {
    // static 으로 singleton 이라는 인스턴스를 생성한다.
    private static Singleton instance;
    private int count = 0;

    // 생성자는 private으로 막아놓는다.
    // 다른 클래스에서 해당 객체를 new로 생성하는것을 막기 위함이다.
    private Singleton(){};

    // static method로 인스턴스를 가져온다.
    public static Singleton getInstance(){
        // 이때 인스턴스가 만약 존재 하지 않다면 생성해서 반환한다.
        // 한번 생성이 된 인스턴스는 해당 if문을 거치지 않고 그 객체가 그대로 반환된다.
        if(instance == null){
            instance = new Singleton();
        }
        return instance;
    }

    public int nextCount(){
        return count++;
    }

}

위의 코드는 싱글톤 패턴으로 인스턴스를 생성하는 코드이다.
인스턴스를 처음 호출할 때 인스터스를 생성하고 그 다음부터는 생성된 인스턴스를 계속 재사용 하는 방식이다.


싱글톤 패턴 코드의 공통점은 3가지 정도가 있다.
첫번째로 static Initialization으로 초기화를 static으로 선언한다.
두번째로는 private constructor이다. 생성자를 private으로 막아두어 다른 방식의 객체 생성을 막는다.
마지막 세번째로는 public method이다. 인스턴스를 가져오는 메서드를 public으로 선언하여 객체를 가져오는 메서드를 열어둔다.


위의 코드는 가장 흔한 싱글톤 패턴의 코드이며,
다양한 방식이 존재하고, 멀티 스레드환경을 고려한 코드또한 구글링을 통하면 많이 접할 수 있다.

그렇다면 일반 객체 생성과의 차이점을 알아보기위해 test를 해보겠다.


Test.class

public class Test {
    public static void main(String[] args) {
        System.out.println("출력");
        for(int i = 0; i< 10; i++){
            Singleton singleton = Singleton.getInstance();
            System.out.println(singleton.toString());
        }
    }    
}
/*
출력
Singleton@39ed3c8d
Singleton@39ed3c8d
Singleton@39ed3c8d
Singleton@39ed3c8d
Singleton@39ed3c8d
Singleton@39ed3c8d
Singleton@39ed3c8d
Singleton@39ed3c8d
Singleton@39ed3c8d
Singleton@39ed3c8d 
*/

위의 출력과 같이 객체를 계속 호출해도 같은 객체가 나오게 된다.
nextCount메서드로 객체 내의 변수값을 증가시키는 경우에도, 같은 객체에서 이뤄지기 때문에 잘 적용된다.


이렇게 간단하게 싱글톤에 대해서 알아보았다.
하지만 싱글톤 패턴에도 문제점은 존재한다고 한다.
동시성을 고려해야 하며, 객체간의 결합도를 높여 문제를 야기할 수 있고,
SOLID원칙을 위반할 가능성이 크며, 멀티스레드 구현에서 동기화문제가 생길 수 있다고 한다.


느낀점

Spring Boot를 공부하면서 @Autowried 혹은 다양한 애너테이션으로 싱글톤을 손쉽게 편하게 구현했었는데,
이렇게 Java 코드로만 싱글톤을 구현하니 어떻게 동작하는 건지에 대한 이해도가 더 상승한거 같다.

몇가지 디자인패턴을 더 공부해서 코드로 짜보면서 이렇게 글로 남기면서 공부해 나아가야겠다.

728x90
반응형