[CS] Singleton Pattern

do yeon kim·2022년 10월 6일
0

Singleton Pattern ??

싱글톤패턴은 디자인패턴의 생성패턴으로 클래스에서 객체를 구성하는 방법과 관련된 디자인 패턴 중 하나이다.

single이라는 단어의 뜻은 "한 개" 또는 "단일" 이라는 의미이다.



뭐가 "한 개" 인가?

싱글톤패턴은 하나의 클래스에 하나의 인스턴스만을 가지는 패턴이다.

일반적인 코드 구현시, 우리는 클래스를 정의하고 필요에 따라서 클래스를 이용해서 객체를 인스턴스화 해서 해당 객체를 사용한다. 이때 힙메모리에 인스턴스가 생기게 된다. 만약 여러개의 객체를 만들게 된다면, 각각의 객체 마다 모두 힙메모리에 자기만의 주소공간을 가지게 된다. 주소공간에는 해당 객체가 사용하는 변수, 데이터 등이 보관되게 된다. 그리고 이 주소공간에 있는 데이터는 각각의 객체마다 모두 다르게 된다.

하지만 경우에 따라서 시스템에 해당 클래스로 만들어지는 객체가 오로지 하나여만 하는 경우도 있을 수 있다. 이때 하나의 인스턴스만 생성하고, 이후 객체를 생성하고자 하는 경우 이미 만들어진 앞의 인스턴스를 사용하는 경우가 싱글톤패턴이라고 할 수 있다.



데이터베이스 연결모듈? 싱글톤패턴?

예로 데이터베이스의 연결모듈에 싱글톤패턴이 사용된다.
데이터베이스에 연결하는 모듈이 여러개라고 가정해보자.

a라는 객체가 연결하고, b라는 객체가 연결한다고 가정하면,
a는 a만의 주소공간을 가지고서 데이터베이스를 가지고 작업을 한다.
b는 b만의 주소공간을 가지고서 데이터베이스를 가지고 작업을 한다.

모든 작업이 끝난 후 원본 데이터베이스의 데이터들은 a,b작업의 결과가 모두 반영이 되지 않거나, 원하던 결과와는 다른 결과물을 도출할 수도 있을 것이다.

(위 설명이 맞는지 아닌지는 잘 모르겠다.아마 아닐거 같다. 맞는건가?)



그래서 왜 사용하는가?

싱글톤 패턴을 이용하면 클래스에 대한 단일객체를 생성하게 되므로 메모리 낭비를 줄일 수 있다.
그리고 전역객체를 제공함으로, 어디서든 접근할수있게한다(?) 또한 공유된 리소스에 동시접근을 제어한다.



생성자 제한

싱글톤 패턴을 구현 시 고려해야 되는 것이 생성자를 제한하는 것이다.
생성자를 클래스 자체에서만 접근할 수 있도록 private로 설정해주어야 한다. 그렇지 않으면, 다른 곳에서 새롭게 인스턴스를 생성할 수 있게 된다.



인스턴스 생성 시기

인스턴스가 언제 생성되는 가에 따라서 사전초기화(Eager initialization)와 늦은초기화(Lazy initialization)가 있다.

  • 사전초기화(Eager initialization)
    클래스가 호출될 때 인스턴스를 생성하는 방법이다. 인스턴스가 실제로 사용하지 않아도 생성되기 때문에 메모리를 낭비한다는 단점이 있다.

  • 늦은초기화(Lazy initialization)
    인스턴스를 실제로 사용하려고 하는 시점에 인스턴스가 생성하는 방법이다.
    사용가능한 리소스가 제한적인 상황에서 사용되어지는 방법이다.



Singleton pattern 구현

그래서 어떻게 singleton pattern을 구현하는가

먼저 사전초기화 방법을 이용한 구현이다.
싱글톤 패턴 객체를 생성할 때 이미 만들어진 객체가 있다면, 만들어진 객체를 반환하고 아니라면 새로운 객체를 만들어서 반환한다.

# 사전초기화
class Singleton(object):
    def __new__(cls):
        if not hasattr(cls, 'instance'):
            cls.instance = super(Singleton, cls).__new__(cls)
        
        return cls.instance

a = Singleton()
b = Singleton()
print(a.instance)
print(b.instance)
print(a == b) # True
# 늦은초기화 방법
class Singleton:
    _instance = None
    def __init__(self):
        if not Singleton._instance:
            print("__init__ method called but nothing is created")
        else:
            print("instance already created:", self.get_instance())
    
    @classmethod
    def get_instance(cls):
        if not cls._instance:
            cls._instance = Singleton()
        return cls._instance

a = Singleton()
a.get_instance() # 실제 사용되는 시점
b = Singleton()


단점

싱글톤 패턴의 단점은 하나의 인스턴스만 제공하기 때문에 TDD의 환경에서는 테스트가 어렵다는 점이다. 단위테스트의 경우 독립적으로 테스트가 이루어져야 하는데, 싱글톤패턴을 이용하게 되면, 하나의 인스턴스를 기반으로 동작하기 때문에 독립적인 인스턴스를 만들기 어렵다는 점이 있다.

또한 모듈간의 결합을 강하게 만든다는 단점이 있다.
이는 의존성 주입을 통해서 모듈간의 결합을 느슨하게 만들 수 있다.



추가 학습내용

  • __init__ vs __new__ vs __call__
  • 의존성 주입
  • self vs cls

0개의 댓글