순간을 기록으로

[디자인패턴] 싱글톤 패턴 1부 자바 본문

Computer Science/DesignPattern

[디자인패턴] 싱글톤 패턴 1부 자바

luminous13 2021. 12. 28. 12:41

안녕하세요. 오늘은 싱클톤 패턴에 대해 알아보겠습니다.

 

싱글톤 패턴

싱글톤 패턴이란 인스턴스를 오직 한 개만 제공하는 클래스를 만드는 패턴입니다. 인스턴스가 무조건 한개여만 됩니다.

 

예를들어 오버워치를 하고 있는데 마우스 속도가 너무 느린거에요. 셋팅창을 열어 마우스 감도를 90으로 올렸어요. 그런데 이번에는 너무 마우스가 빨라서 속도를 다시 줄이려 마우스 감도를 60으로 줄이려고해요. 이때 만약 셋팅창 인스턴스가 여러개면 어떤 셋팅창에는 마우스 감도가 90이고 어떤 채팅창에는 마우스 감도가 60이라서 문제가 발생하게되죠. 이럴 때 싱글톤 패턴을 이용해서 문제를 해결하게 됩니다.

 

코드로 살펴보기

우선 App.java와 Settings.java파일을 만듭니다.

 

public class Settings {

}
public class App {

    public static void main(String[] args) {
        Settings settings1 = new Settings();
        Settings settings2 = new Settings();

        System.out.println(settings1 != settings2);
    }
}

다음과 같이 코드를 작성한 후 실행하면 출력결과로 true가 나오게 됩니다.

그 이유는 new를 이용해서 서로다른 셋팅 인스턴스 2개를 만들었기 때문이에요.

 

싱글톤패턴을 적용하려면 new를 사용해서 외부에서(=Settings 클래스 밖) 인스턴스 생성하는 것을 막아야 합니다.

막기 위해서는 Settings에 private 생성자를 만들면 됩니다.

 

public class Settings {
    private Settings() {
    }
}

이렇게 private 생성자를 만들면 다음과 같이 외부에서 인스턴스를 생성할 수 없게 됩니다. 

 

 

자 외부에서 new를 통한 직접적인 인스턴스 생성을 막았으니 Settings 클래스는 인스턴스를 간접적으로 제공하는 방법을 만들어야됩니다. 그러면 코드를 다음과 같이 짜면 됩니다.

 

 

Settings.java

public class Settings {
    private Settings() {
    }

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

 

App.java

public class App {

    public static void main(String[] args) {
        Settings settings1 = Settings.getInstance();
        Settings settings2 = Settings.getInstance();

        System.out.println(settings1 != settings2);
    }
}

이렇게 하면 간접적으로 Settings의 인스턴스를 받게 됩니다. 그럼 같은 인스턴스를 반환하게 될까요?? 실행을 해보면 true 즉 다른 인스턴스라고 나옵니다. Settings는 인스턴스를 new를 통한 직접제공에서 static 메소드를 이용해 간접적으로 제공하는 것으로 바꿨지만 여전히  다른 인스턴스를 생성해서 주고 있게 됩니다.

 

같은 인스턴스를 제공하려면 Settings 안에 Settings를 담을 static 참조변수를 만듭니다. 그리고 인스턴스 제공 메소드에 인스턴스가 없다면 인스턴스를 생성하고 있다면 이미 있는 인스턴스를 반환하는 로직를 짭니다.

 

Settings.java

public class Settings {
    private static Settings instance;

    private Settings() {
    }

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

        return instance;
    }
}

이렇게 코드를 작성한 후 실행하면 false가 나옵니다. 우리의 목표인 하나의 인스턴스만 만들고 그 인스턴스를 반환하는 것을 달성했습니다.

 

이 방법이 싱글톤 패턴을 만드는 가장 기본적인 방법입니다.

하지만 여기에 심각한 문제가 있습니다.

웹애플리케이션을 만들 때 멀티쓰레드를 자주 사용하게 됩니다. 그런데 멀티쓰레드 환경에서 위의 코드는 안전하지 않습니다. 멀티쓰레드에서도 싱글톤을 안전하게 사용하는 방법은 다음에 포스팅하겠습니다.

 

복습

  1. 생성자를 private로 한 이유는 무엇인가요?
    • 외부에서 new를 이용한 객체 생성을 막기위해서 입니다. new를 통해 인스턴스가 생성되면 그 이후 반드시 생성자가 호출되어야 합니다. 하지만 private 메소드는 해당 클래스 내부에서만 메소드를 호출이 허용되므로 외부에서 생성자를 호출할 수 없습니다.
  2. getInstance() 메소드를 static으로 선언한 이유?
    • static 메소드가 아니면 인스턴스를 생성한 이후에 메소드에 접근할 수 있기 때문입니다.
  3. getInstance()가 멀티쓰레드 환경에서 위험한 이유는 무엇인가요?
    • 웹애플리케이션은 멀티쓰레드를 사용하게 되는데. 위의 코드는 동시에 접근하는 쓰레드를 처리하지 못하기 때문입니다.
Comments